3

I am just learning socket programming on Linux by some websites and here are some parts of my code on server side by using TCP:

#define BufferLength 100
#define SERVPORT 3111
int main()
{
  /* Variable and structure definitions. */
  int sd, sd2, rc, length = sizeof(int);
  int totalcnt = 0, on = 1;
  char temp;
  char buffer[BufferLength];
  struct sockaddr_in serveraddr;
  struct sockaddr_in their_addr;
  fd_set read_fd;

  /* Get a socket descriptor */
  if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  {
    perror("Server-socket() error");
    exit (-1);
  }
  else
    printf("Server-socket() is OK\n");

  /* Allow socket descriptor to be reusable */
  if((rc = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) < 0)
  {
    perror("Server-setsockopt() error");
    close(sd);
    exit (-1);
  }
  else
    printf("Server-setsockopt() is OK\n");

  /* bind to an address */
  memset(&serveraddr, 0x00, sizeof(struct sockaddr_in));
  serveraddr.sin_family = AF_INET;
  serveraddr.sin_port = htons(SERVPORT);
  serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
  printf("Using %s, listening at %d\n", inet_ntoa(serveraddr.sin_addr), SERVPORT);

  /* continue */
}

When I did the last line (printf("using......")), I got a segmentation fault, why? Thanks.

21
  • 1
    Your code looks good, and it works for me. Running it under valgrind does not reveal any memory-related issues that would explain a segfault. I did add all the requisite headers; I guess there's a chance that your problem arises from you missing one or more of those. Does your compiler emit any warnings? Commented May 11, 2015 at 15:40
  • Hi John, there is no warning when I compile this program. Also, when I run similar code with this, I don't have any segmentation error. Commented May 11, 2015 at 15:45
  • 1
    @user, the code you presented is fine. Supposing that you included all the needed headers in the full translation unit from which you built the program -- and your compiler should have complained if you did not -- I am inclined to believe that the given code does not correspond to the program that segfaulted on you. Commented May 11, 2015 at 16:03
  • 1
    Hmm. I agree with @John, nothing jumps out at me. Recommend using a local variable on the inet_ntoa result and inspecting is (via debugger) before the print...maybe you are somehow getting a bad pointer return? Commented May 11, 2015 at 16:04
  • 1
    You would be well advised to follow @Speed8ump's advice to sort this out via a debugger. Accepting the return value of inet_ntoa() in a local variable, as he suggests, will make that a bit more convenient. Commented May 11, 2015 at 16:09

2 Answers 2

3

The code as shown misses to #include any headers, so as it stands won't compile due to some undefined symbols.

It would compile however if you missed to just prototype any library functions referenced by the code, which would lead to any function being assumed to return int.

The latter fact might be fatal or not.

On a 64bit system at least it is fatal in the case of inet_ntoa() used as a parameter to printf(), as on a 64bit system it most likely is expected to return a 64bit (char-pointer) value (but a 32bit int). So (assuming the prototype misses) when generating the code the compilers assumes inet_ntoa() to return a 32bit int which would lead to "chopping-off" the most significant 32bits of the address returned. Trying to printf() from such a "crippled" and therefore (most likely) invalid address provokes undefined behaviour and in your case leads to the segmentation violation observed.

To fix this, add the relevant prototype (for inet_ntoa()) by adding:

#include <arpa/inet.h>

The compiler should have warned you about this. To enable all compiler's warnings for gcc use the options -Wall -Wextra -pedantic. Take such warnings serious.

Sign up to request clarification or add additional context in comments.

Comments

0

It seems likely that inet_ntoa() is somehow returning NULL, leading to the segfault when it is dereferenced in the printf(). I can't find a direct reference plainly stating that this is possible with the Linux version of inet_ntoa, but I found several people who made that claim, and it is the only point in that code where a pointer is being dereferenced.

The answer at the bottom of this question: segmentation fault for inet_ntoa makes the claim that inet_ntoa can return NULL. However, following his reference links, I couldn't find an actual statement of that fact.

There is an MSDN article (which is suggestive, but of course doesn't apply directly to Linux code) that does state plainly that inet_ntoa() can return NULL here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms738564%28v=vs.85%29.aspx

2 Comments

Hard to believe it returns NULL for INADDR_ANY. Hard to believe there is such a thing as a possible error in a 32-bit argument value in the first place.
Kind of agree with you on the first point, but there aren't many other candidates there for a segfault, which leads me to this as the only possible candidate, even if unlikely. As far as error from a 32-bit argument, aren't there a fairly large number of values that would not translate into valid 32-bit IP addresses?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.