-2

I'm really confused. I have a C server and it was working great, but then I added some code, and I thought it was working fine until my c program randomly started changing the value of an int to a negative value.

Basically I'm having my server output the total bytes sent and midway through the transmission, always around 2100000000 bytes, the total bytes becomes negative. Here's an example of my output file. The value can't just become negative if you look at my code. So I suspect it's something weirder.

"345000","1470253912","59203","5592","2069901108"
"348000","1470253912","475539","4194","2092449162"
"351000","1470253912","830291","2796","2112043464"
"354000","1470253913","243217","1398","2133985176"
"357000","1470253913","708686","13980","-2135434834"
"360000","1470253914","173646","9786","-2109094024"
"363000","1470253914","514938","6990","-2089413400" 

Anyways the thing I added, I commented it out, and I still came across the same error. Just for reference it's commented out in my code under tags "NEW STUFF ADDED". (I added it because of this post: Terminating C program on command line, but make sure writer is finished writing )

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <sys/wait.h>
    #include <signal.h>
    #include <sys/time.h>



int PORT_NUM = 0; 
int RecordRate = 3000; 
FILE *fp;

typedef struct timeval timeval;
timeval time_;


void error(const char *msg)
{
    perror(msg);
    exit(1);
}

 //NEW STUFF ADDED
 //void sig_handler(int signo)
 //{
 //  if (signo == SIGINT) {
 // printf("received SIGINT\n");
 // exit(0);
 // fflush(fp);
 // }
 //}

 int main(int argc, char *argv[])
 {
     int sockfd, newsockfd, portno;
     socklen_t clilen;
     char buffer[1000000];
     struct sockaddr_in serv_addr, cli_addr;
     int n;



     PORT_NUM = atoi(argv[1]);  
     fp = fopen(argv[2],"w");   

//       NEW STUFF ADDED
//       if (signal(SIGINT, sig_handler) == SIG_ERR)
//       printf("\ncan't catch SIGINT\n");

     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0) 
            error("ERROR opening socket");
     bzero((char *) &serv_addr, sizeof(serv_addr));
     //portno = atoi(argv[1]);
     portno = PORT_NUM;
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(portno);
     if (bind(sockfd, (struct sockaddr *) &serv_addr,
                        sizeof(serv_addr)) < 0) 
                        error("ERROR on binding");
     listen(sockfd,10);
     clilen = sizeof(cli_addr);



     newsockfd = accept(sockfd, 
                             (struct sockaddr *) &cli_addr, 
                             &clilen);
     if (newsockfd < 0) 
                error("ERROR on accept");


    int counter = 0;    
    int total_bytes_sent = 0;

     while(1){  

     bzero(buffer,1000000);
     n = read(newsockfd,buffer,999999);


     if (n < 0) {
     error("ERROR reading from socket");
     }
     else if (n != 0) {





             total_bytes_sent += n;
             gettimeofday(&time_, NULL);

             if(counter%RecordRate==0){
             printf("counter  %d \n", counter); 
             printf("Bytes Sent  %d \n", total_bytes_sent);
             fprintf(fp,"\"%d\",\"%ld\",\"%d\",\"%d\",\"%d\"\n", counter, time_.tv_sec, time_.tv_usec, n,total_bytes_sent);
             }




             counter++; 



     }

     }
     fclose(fp);
     close(newsockfd);
     close(sockfd);
     return 0; 
 }

I swear I'm not trolling. I feared it was what I added that did this, but once I commented it out I got the same error. The thing is the error only became present after I added the code. So causation, correlation, no link?

How can this happen? And why always around 2100000000 bytes.

It's not the end of the world. I mean I can just hardcode something that makes sure the value is always, positive but I'm curious as to how this happens. Thanks.

Community
  • 1
  • 1
Vishnu Murale
  • 173
  • 14
  • 1
    Around `2100000000` is around `2147483647`, which is the maximum 32 bit `int` number. You take it from here. – Eugene Sh. Aug 03 '16 at 20:23
  • Perhaps you need to change that `int` to `unsigned`. Assuming an `int` is four bytes. `2100000000` is close to `0x80000000`, which would be considered negative. – Fiddling Bits Aug 03 '16 at 20:25
  • Unigend will just move his problem fromhappening at 2 and a bit GB to happen at 4 and bit GB. 32bit is simply not enough for this use case, and he should be using a 64bit datatype. – jsbueno Aug 03 '16 at 20:28
  • Apparently a checking should be added to avoid stuff like Y2K bugs.. – Eugene Sh. Aug 03 '16 at 20:31
  • Note that the behaviour you're describing is not random (as the title suggests); it is readily reproducible and the change is systematic. – Jonathan Leffler Aug 03 '16 at 20:43

1 Answers1

6

Simply because ordinary signed int variables overflow at 231-1 (2147483647) and become negative.

Since this order of magnitude is not enough to keep track of the values you need, you should be using a 64bit variable to that - declare your variable as long long - and take proper care of this change in the places you are outputting this value to a text stream, and you should be good.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
jsbueno
  • 99,910
  • 10
  • 151
  • 209
  • Oh gee. lol. Thanks – Vishnu Murale Aug 03 '16 at 20:25
  • 2
    Technically, when the signed integer overflows, you incur undefined behaviour. However, the most common manifestation of undefined behaviour is indeed a wraparound to the most negative number (-2147483648) and then proceeding from there. It is not safe to assume that is what will happen, though. – Jonathan Leffler Aug 03 '16 at 20:32
  • 1
    @Jonathan: but it is (pretty) safe to assume that that is happening here, I think. – Rudy Velthuis Aug 03 '16 at 20:37
  • 1
    @RudyVelthuis: that's what seems to be happening with the current compiler on the OPs current system. Don't forget, though, that the compiler writers are for ever on the lookout for ways to (make life difficult for programmers) optimize code, and their optimizations can assume that [undefined behaviour is not invoked](http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html), and things can go haywire after the next compiler upgrade, or when you switch platforms, etc. Be very, very cautious about invoking undefined behaviour. (No: I'm not happy about it.) – Jonathan Leffler Aug 03 '16 at 20:41
  • @I only meant that this seems to be happening here. I am not saying that one should invoke undefined behaviour, although I bet that on most 32 bit systems, the same will happen. Note that there is enough code that relies on this or similar behaviour, e.g. checksum code, etc. – Rudy Velthuis Aug 03 '16 at 20:51