Search code examples
csocketshostgethostbyname

segmentation fault in printing inet_ntoa function


Consider the following program:

#include <sys/socket.h> 
#include <stdio.h> 
#include <netinet/in.h>
       #include <arpa/inet.h>
       #include <string.h>
#include <netdb.h> 

void printhost(char* pLocalHostAddress )
{
   struct hostent * pHost;
   struct in_addr   **pptr;
   char hostName[128]="\0";

   gethostname(hostName, sizeof(hostName)); 
   printf("%s",hostName);
   if( NULL != (pHost = gethostbyname(hostName)) )
   {
      memcpy( pLocalHostAddress, *pHost->h_addr_list, 4);
      printf("ip address: %s\n",inet_ntoa(**(struct in_addr **)&pLocalHostAddress));
   }
}
void main()
{
   char pLocalHostAddress[50];
   printhost((char *)pLocalHostAddress);
           printf("ip address: %s\n",inet_ntoa(**(struct in_addr **)&pLocalHostAddress));

}

Strangely, it is printing host IP address correctly when I try to print inside printhost() function, but giving segmentation fault when I try to print from main() function. Can anybody please clarify?


Solution

  • Note: I'm not familiar with the functions in question but basing my answer on this explanation and this documentation.

    Replace the function with:

    struct in_addr *printhost(void)
    {
    // ... 
        if( NULL != (pHost = gethostbyname(hostName)) )
        {
            struct in_addr *tmp = (struct in_addr *)*pHost->h_addr_list;
            printf("ip address: %s\n",inet_ntoa(*tmp));
            return tmp;
        }
        return NULL;
    }
    

    and call it like:

    struct in_addr *p = printhost();
    if ( p )
        printf("ip address: %s\n",inet_ntoa(*p));
    

    Your code causes undefined behaviour in several ways. When undefined behaviour is triggered, anything can happen, including the same code appearing to work in one place and not work in another. It is futile to analyze this in too much depth, instead it is better to fix the code.

    memcpy( pLocalHostAddress, *pHost->h_addr_list, 4); copies the first 4 bytes of a struct in_addr into the start of the 50-byte buffer in main. I'm going to assume that sizeof(struct in_addr) is actually 4 bytes on your system as suggested by this page otherwise your code is even worse. In general, you should use sizeof expressions to work out how much to copy.

    Then you pass that struct in_addr to inet_ntoa which is OK. In your function, &pLocalHostAddress is the address of a pointer to a buffer containing the struct in_addr. So you dereference twice to get the struct.

    But in main, &pLocalHostAddress is the address of the buffer containing the struct in_addr. So you should only dereference once. Instead your code tries to interpret the internet address as the bytes of a pointer, causing a segmentation fault when you dereference that pointer.

    Your code would probably appear to work if you changed the code in main to inet_ntoa(*(struct in_addr *)&pLocalHostAddress) , however it is a bad idea to actually persist with such code.