0

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?

Biffen
  • 6,249
  • 6
  • 28
  • 36
pankaj kushwaha
  • 369
  • 5
  • 20
  • 2
    `**(struct in_addr **)&pLocalHostAddress)` - what on earth – M.M Sep 11 '15 at 07:41
  • i have removed c++ :) – pankaj kushwaha Sep 11 '15 at 07:41
  • Arrays decays naturally to pointers (to the first element), you don't need to cast an array to a pointer. – Some programmer dude Sep 11 '15 at 07:41
  • BTW, you have two different variables in your code both named `pLocalHostAddress`. They have different addresses , so you should not expect the same results from aliasing their address – M.M Sep 11 '15 at 07:42
  • As @M.M said, what on earth. Have you maybe looked at the man page for [inet_ntoa](http://linux.die.net/man/3/inet_ntoa)? – Khaled Nassar Sep 11 '15 at 07:44
  • Also, you should probably be using [`inet_ntop`](http://man7.org/linux/man-pages/man3/inet_ntop.3.html) instead, passing `pHost->h_addrtype` to the function. *And* why don't you copy the string directly to `pLocalHostAddress` in your function? – Some programmer dude Sep 11 '15 at 07:46
  • yes i have seen , may be i have misunderstood it , can somebody tell what is wrong in **(struct in_addr **)&pLocalHostAddress) , or what is correct alternative? – pankaj kushwaha Sep 11 '15 at 07:47

2 Answers2

1

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.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
  • thanks for your answer, it will work , but what I am asking that "what is the reason that printf inside function works fine but it give segmentation fault when i try to print it in main function." – pankaj kushwaha Sep 11 '15 at 08:02
  • you are correct , i should not have deference twice in main , its wrong , thanks for your detail answer. – pankaj kushwaha Sep 11 '15 at 08:18
0

I got it , double dereferencing was the problem , as M.M told "you have two different variables in your code both named pLocalHostAddress". following program is working:

#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(pLocalHostAddress);
      printf("ip address: %s\n",inet_ntoa(*(struct in_addr *)pLocalHostAddress));
}
pankaj kushwaha
  • 369
  • 5
  • 20