CS Student
CS Student

Reputation: 1643

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?

Upvotes: 1

Views: 291

Answers (2)

user2736738
user2736738

Reputation: 30936

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.

Upvotes: 1

user7860670
user7860670

Reputation: 37587

getaddrinfo function will assign a value to pointer to which the passed argument points to. In the first case you are directly passing the value of uninitialized local variable results so it does not really point anywhere and dereferencing it leads to undefined behavior (which manifests itself into crash). In the second case you are passing a pointer to results local variable, which will point at the first addrinfo structure if function succeeds.

Upvotes: 0

Related Questions