Search code examples
csocketspointersstructgetaddrinfo

Pointer to pointer to struct causing segfault using getaddrinfo()


I'm using the getaddrinfo() function that requires a struct addrinfo ** to populate with a linked list of results, but I'm getting a segfault when I try the following code...

int main() {
    struct addrinfo **results;
    getaddrinfo("localhost", "http", NULL, results); // segfault here
    return 0;
}

I'm passing the struct addrinfo **results to getaddinfo() which expects that type, how is a segfault being caused?

If I change my code slightly to this...

int main() {
    struct addrinfo *results;
    getaddrinfo("localhost", "http", NULL, &results); // works        
    return 0;
}

my code works fine. Whats the difference?


Solution

  • The results will eventually point to a linked list of struct addrinfos, and you can go through this list to get all the addresses that match what you passed in with the third parameter. Function will make a pointer point to a linked list and that's why the address of a pointer is expected. When you pass a struct addrinfo* variable's address, it can be made point to the list. Dereference the passed vaiable will be alright, because the dereferenced value is that of the variable results. (This explains why struct addrinfo *results; and &results works).

    Why the error occured ?

    It makes point to the linked list. In the source of getaddrinfo from here

    2201    int
    2202    getaddrinfo (const char *name, const char *service,
    2203                 const struct addrinfo *hints, struct addrinfo **pai)
    2204    {
    ...
    ...
    2535      if (p)
    2536        {
    2537          *pai = p; // in your case this (pai) was uninitialized
    2538          return 0;
    2539        }
    2540    
    2541      return last_i ? -last_i : EAI_NONAME;
    2542    }
    

    In your case you provided an uninitialized value. Dereferencing it is undefined behavior. In your case it resulted in segmentation fault.

    To clarify further this would also work

    int main(void) {
        struct addrinfo *results;
        struct addrinfo **results_addr =  &results;
        getaddrinfo("localhost", "http", NULL, results_addr); // works        
        return 0;
    }
    

    But well the example above is just for the illustration purpose that it is not the double pointer passed was the issue rather initializayion was. Just pass &result which is much more clear and readable.