3

I have a random segfault in my code when I try to browse my structure array.

I have a struct_fd which contains the value of a socket, its type, 2 buffers and 2 pointers to function. I also have my main server "env" structure (struct s_sv_prop) that contains a pointer to an array of struct_fd.

Header :

#define MAX_CLIENTS     10
#define MAX_SOCKETS     1 + MAX_CLIENTS
#define SK_SERV         0
#define SK_CLIENT       1
#define SK_FREE         2

typedef struct s_fd         t_fd;
typedef struct s_sv_prop     t_sv_prop;

struct          s_fd
{
    void    (*ft_read)();
    void    (*ft_write)();
    int     sock;
    int     type;
    char     rd[BUF_SIZE + 1];
    char    wr[BUF_SIZE + 1];
};

struct          s_sv_prop
{
    t_cmd           *cmd;
    t_fd            *fds;
    fd_set          readfds;
    fd_set          writefds;
    int             max;
    int             left;
    int             port;
};

Function where I allocate memory for my array of structure :

void                init_sv_prop(t_sv_prop *sv, char *port, char **env)
{
    int             i;

    i = 0;
    sv->max = 0;
    sv->left = 0;
    check_port(port);
    sv->port = (unsigned short) atoi(port);
    sv->cmd = (t_cmd *)malloc(sizeof(*(sv->cmd)));
    init_env(sv, env); /* initiate other env */
    init_command_list(sv); /* malloc an array of another struc */
    sv->fds = (t_fd *)malloc(sizeof(*(sv->fds)) * MAX_SOCKETS);
    while (i < MAX_SOCKETS) {
        clean_fd(&(sv->fds[i]));
        i++;
    }
}

I use clean_fd to clean all possible memory issue right after the malloc:

void        clean_fd(t_fd *fd)
{
    fd->type = SK_FREE; /* Valgrind : Invalid write of size 4 */
    fd->sock = 0;
    bzero(fd->rd, BUF_SIZE + 1);
    bzero(fd->wr, BUF_SIZE + 1);
    fd->ft_read = NULL;
    fd->ft_write = NULL;
}

Enventually when I want to display the state of my structure I randomly have a EXC_BAD_ACCESS segfault (not every time though...) :

void            sv_socket_state(t_sv_prop *sv, char *tag)
{
    int     i;
    char    *str;
    char    skfr[] = "FREE";
    char    sksv[] = "SERVER";
    char    skcl[] = "CLIENT";

    i = 0;
    while (i < MAX_SOCKETS)
    {
        if (sv->fds[i].type == SK_SERV)
            str = sksv;
        else if (sv->fds[i].type == SK_CLIENT)
            str = skcl;
        else
            str = skfr;
        printf("%5d | %6s | %5d | %6c | %6c\n", i, str, CL_SOCK(i),
            (FD_ISSET(CL_SOCK(i), &sv->readfds) ? 'X' : ' '),
            (FD_ISSET(CL_SOCK(i), &sv->writefds) ? 'X' : ' '));
        i++;
    }
}

When I run my code on OsX, as said previously, I randomly have a segfault when running the last function. When I run it on Ubuntu, I got a malloc error and valgrind detects an invalid write error.

I must miss something the my allocations. Do you have an idea of where the problem comes from ?

Paul Floyd
  • 5,530
  • 5
  • 29
  • 43
valvince
  • 397
  • 1
  • 13
  • 2
    Please [see why not to cast](http://stackoverflow.com/q/605845/2173917) the return value of `malloc()` and family in `C`. – Sourav Ghosh Jun 25 '15 at 09:32
  • I deleted the cast, still get the issue. – valvince Jun 25 '15 at 09:41
  • @OP no no, that is not the asnwer, just a suggestion. You mind showing us the `t_fd` structure? – Sourav Ghosh Jun 25 '15 at 09:43
  • I've edited to add "define" in the header. I'v omitted the other structures part of t_sv_prop that are also initiated using malloc for clarity but I can add them if required. – valvince Jun 25 '15 at 09:48
  • 4
    `sizeof(*(sv->fds)) * MAX_SOCKETS` => `sizeof(*(sv->fds)) * 1 + MAX_CLIENTS` : So need parentheses. – BLUEPIXY Jun 25 '15 at 09:58
  • You might like to read about the pre-processor in general and how `#define`s are handled in particular. `#define`s are not variables! – alk Jun 25 '15 at 10:07
  • @BLUEPIXY : Ahh thanks... My macro caused an obvious error in malloc size... I'll be more carefull with macro next time. Alk do you know a good solution on how to define MAX_SOCKETS accourding to MAX_CLIENTS all over the code ? Thanks all for your help – valvince Jun 25 '15 at 10:23
  • `#define` are ok for this. Just use them appropriate .. ;-) – alk Jun 25 '15 at 10:33
  • regarding this line: (and one other of a similar nature) 'sv->cmd = (t_cmd *)malloc(sizeof(*(sv->cmd)));' 'sizeof' is a compile time entry, not a run time entry. There is no way for the sizeof( *sv->cmd) to know the number of bytes, at compile time, for the memory pointed to by sv->cmd at run time – user3629249 Jun 25 '15 at 22:11
  • To assure the malloc operation was successful, always check (!=NULL) the returned value. – user3629249 Jun 25 '15 at 22:13

1 Answers1

3

As BLUEPIXY said in the comments, the line :

sv->fds = (t_fd *)malloc(sizeof(*(sv->fds)) * MAX_SOCKETS);

is in fact:

sv->fds = (t_fd *)malloc(sizeof(*(sv->fds)) * 1 + MAX_CLIENTS);

and caused the malloc to be the size of *(sv->fds) + the value of MAX_CLIENTS. The macro has to go from:

#define MAX_SOCKETS     1 + MAX_CLIENTS

to:

#define MAX_SOCKETS     (1 + MAX_CLIENTS)

Thanks all for your help.

Community
  • 1
  • 1
valvince
  • 397
  • 1
  • 13