-1

I'm quite new to C and run into strange problem that I can not explain or solve.

#include <netinet/in.h>
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>

void main ()
{
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in sock_addr;
    sock_addr.sin_family = AF_INET;
    sock_addr.sin_port = htons(1500);
    connect(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
    puts("A");
    char foo[9];
    puts("B");
    close(sock);
}

Code above prints out following lines:

A
B

If I comment out char foo[9] or change 9 to some smaller value then nothing is being printed out and program hangs. Looks like connect is that makes program to freeze but I don't see anything wrong on that line.

How to fix above code so that char foo[9] can be removed and program still prints out A and B and then exits? Why completely unrelated char foo[9] avoids program to freeze?

I'm using GCC 6.3.0 on Ubuntu.

Karmo Rosental
  • 643
  • 1
  • 8
  • 18
  • 1
    See [What should `main()` return in C and C++](http://stackoverflow.com/questions/204476/) for reasons why `int main(void)` is preferable to `void main()`. On Linux, `void main()` is plain wrong! You might have wriggle room on Windows. – Jonathan Leffler Sep 02 '17 at 21:13
  • Have you tried error checking the system calls? You set the port and family but not the IP address when you try to connect — that is dubious at best, erroneous at worst. I'm not immediately sure why it causes the symptoms you're seeing, but there are problems en route to where the trouble occurs. It could be that your changed code changes the IP address part of `sock_addr` and your system is hanging trying to contact an uncontactable machine. How long have you waited before deciding the program's frozen? Add `fprintf(stderr, "BC\n");` before the `connect` and `fprintf(stderr, "AC\n");` after? – Jonathan Leffler Sep 02 '17 at 21:18
  • 1
    even more, the sock address is not initialized. it contains trash. What are you connecting to? – Serge Sep 02 '17 at 21:22
  • 1
    Are you using the optimizer at all? Do you compile with warnings enabled, such as warnings for unused variables? (Use `gcc -Wall -Werror -Wextra -Wstrict-prototypes -Wmissing-prototypes` as a starting point — if it doesn't compile cleanly under those options, it quite possibly won't run cleanly either.) – Jonathan Leffler Sep 02 '17 at 21:23
  • `$ gcc -Wall -Werror -Wextra -Wstrict-prototypes -Wmissing-prototypes prog.c -o prog $ ./prog BC` When compiled using online gcc compilers then it doesn't freeze. I upgraded to GCC 7 and it still freezes. When compiled with clang 4.0 then it doesn't freeze. – Karmo Rosental Sep 02 '17 at 21:31
  • 1
    But the code still doesn't initialize the `sock_addr` variable properly — it doesn't set the `sin_addr` at all, so you're connecting to an indeterminate IP address (you've literally no idea what you're trying to connect to). At minimum, use `struct sockaddr_in sock_addr = { 0 };` to set it to zeros. Or use `memset(&sock_addr, '\0', sizeof(sock_addr));`. You're invoking undefined behaviour because you don't initialize the structure properly. And variable responses from compilers and optimizers is symptomatic of undefined behaviour. – Jonathan Leffler Sep 02 '17 at 21:35
  • It is connecting to localhost when it's not freezing but your suggestion `struct sockaddr_in sock_addr = { 0 };` helped to avoid freezing in gcc. Thank you a lot! – Karmo Rosental Sep 02 '17 at 21:45

1 Answers1

1

Converting comments to an answer.

The code shown has an incorrect return type for the main() function on Linux. That is required to be int on all systems except Windows — only on Windows can you possibly hope to use void main(). See What should main() return in C and C++ for more information.

#include <netinet/in.h>
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>

int main(void)
{
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    // missed error check - probably not critical
    struct sockaddr_in sock_addr;
    sock_addr.sin_family = AF_INET;
    sock_addr.sin_port = htons(1500);
    // missed intialization of sock_addr.sin_addr - crucial!
    // omitted trace printing before the call
    connect(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
    // missed error check — possibly critical
    // omitted trace printing after the call - not crucial because of puts() calls
    puts("A");
    char foo[9];
    puts("B");
    close(sock);
}
  • Have you tried error checking the system calls? You set the port and family but not the IP address when you try to connect — that is dubious at best, erroneous at worst. I'm not immediately sure why it causes the symptoms you're seeing, but there are problems en route to where the trouble occurs. It could be that your changed code changes the IP address part of sock_addr and your system is hanging trying to contact an uncontactable machine.
  • How long have you waited before deciding the program's frozen?
  • Have you tried adding fprintf(stderr, "BC\n"); before the call to connect() and fprintf(stderr, "AC\n"); after it? Does the call hang?
  • Are you using the optimizer at all?
  • Do you compile with warnings enabled, such as warnings for unused variables? (Use gcc -Wall -Werror -Wextra -Wstrict-prototypes -Wmissing-prototypes as a starting point — if it doesn't compile cleanly under those options, it quite possibly won't run cleanly either. Include -g for debug information and -O3; if you're doing serious debugging in a debugger, then drop the -O3.)

The code doesn't initialize the sock_addr variable properly — it doesn't set the sin_addr at all, so you're connecting to an indeterminate IP address (you've literally no idea what you're trying to connect to). At minimum, use struct sockaddr_in sock_addr = { 0 }; to set it to zeros. Or use memset(&sock_addr, '\0', sizeof(sock_addr));. You're invoking undefined behaviour because you don't initialize the structure properly. And variable responses from compilers and optimizers is symptomatic of undefined behaviour.

Karmo Rosental notes:

It is connecting to localhost when it's not freezing but your suggestion struct sockaddr_in sock_addr = { 0 }; helped to avoid freezing in GCC.

Jonathan Leffler
  • 666,971
  • 126
  • 813
  • 1,185