Question

I'm writing a UDP send/receive function that will timeout when it doesn't get a reply within a certain time, and will resend the packet. I'm using socksetopt to set the timeout and it all seems to work until I get to the final iteration and then a massive error message appears.

My code is here:

int itermax=10;
int itercount=0;

int send_and_receive(void* message, void* reply, int do_send, int expect_reply){
    struct sockaddr_in serv_addr;
    int sockfd, i, slen=sizeof(serv_addr);
    int buflen = BUFLEN;
    void* buf = NULL;
    struct timeval tv;
    int n_timeouts=1;
    int retval;

    printf("N = %d\n", itercount);
    itercount++;

    if ( (strlen(message)) >= BUFLEN)
        err("Message too big");

    buf = malloc(buflen);

    if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
        err("socket");

    tv.tv_sec = 1;
    tv.tv_usec = 0;
    if( setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) < 0 ){
        err("Setting Timout"); 
    }

    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    if (inet_aton(IP_ADDRESS, &serv_addr.sin_addr)==0)
        err("inet_aton() failed\n");

    if(do_send == TRUE){
        strcpy(buf, message);
        if (sendto(sockfd, buf, buflen, 0, (struct sockaddr*)&serv_addr, slen)==-1)
            err("sendto()");
    }

    if (expect_reply == TRUE){
        if( recvfrom(sockfd, buf, buflen, 0, (struct sockaddr*)&serv_addr, &slen) == -1){

            close(sockfd);
            free(buf);
            if(itercount < itermax){
                send_and_receive(message, reply, do_send, expect_reply);
            }
            else{
                perror("recvfrom");
                return -1;
            }
        }
    }

    memcpy(reply, buf, BUFLEN);
    close(sockfd);
    free(buf);
    return 0;
}

And the error message:


recvfrom: Resource temporarily unavailable
*** glibc detected *** : double free or corruption (top): 0x083af008 ***
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6(+0x6e341)[0xa8a341]
/lib/tls/i686/cmov/libc.so.6(+0x6fb98)[0xa8bb98]
/lib/tls/i686/cmov/libc.so.6(cfree+0x6d)[0xa8ec7d]
[0x8048a44]
[0x80489ff]
[0x80489ff]
[0x80489ff]
[0x80489ff]
[0x80489ff]
[0x80489ff]
[0x80489ff]
[0x80489ff]
[0x8048a84]
[0x8048c35]
[0xac000000]
======= Memory map: ========
00173000-00174000 r-xp 00000000 00:00 0          [vdso]
008a6000-008c3000 r-xp 00000000 08:01 2224682    /lib/libgcc_s.so.1
008c3000-008c4000 r--p 0001c000 08:01 2224682    /lib/libgcc_s.so.1
008c4000-008c5000 rw-p 0001d000 08:01 2224682    /lib/libgcc_s.so.1
00a1c000-00b75000 r-xp 00000000 08:01 2362849    /lib/tls/i686/cmov/libc-2.11.1.so
00b75000-00b77000 r--p 00159000 08:01 2362849    /lib/tls/i686/cmov/libc-2.11.1.so
00b77000-00b78000 rw-p 0015b000 08:01 2362849    /lib/tls/i686/cmov/libc-2.11.1.so
00b78000-00b7b000 rw-p 00000000 00:00 0 
00b84000-00b9f000 r-xp 00000000 08:01 2230784    /lib/ld-2.11.1.so
00b9f000-00ba0000 r--p 0001a000 08:01 2230784    /lib/ld-2.11.1.so
00ba0000-00ba1000 rw-p 0001b000 08:01 2230784    /lib/ld-2.11.1.so
08048000-08049000 r-xp 00000000 08:01 667121     /home/james/BitBucket/rtig/Code/c
08049000-0804a000 r--p 00000000 08:01 667121     /home/james/BitBucket/rtig/Code/c
0804a000-0804b000 rw-p 00001000 08:01 667121     /home/james/BitBucket/rtig/Code/c
083af000-083d0000 rw-p 00000000 00:00 0          [heap]
b7600000-b7621000 rw-p 00000000 00:00 0 
b7621000-b7700000 ---p 00000000 00:00 0 
b7732000-b7733000 rw-p 00000000 00:00 0 
b7745000-b7748000 rw-p 00000000 00:00 0 
bfc70000-bfc85000 rw-p 00000000 00:00 0          [stack]
Aborted

Any help here would be greatly appreciated.

Was it helpful?

Solution

A double free is occurring because you free the buffer here:

if( recvfrom(sockfd, buf, buflen, 0, (struct sockaddr*)&serv_addr, &slen) == -1){
    close(sockfd);
    free(buf);

And then again when you exit the function:

memcpy(reply, buf, BUFLEN);
close(sockfd);
free(buf);
return 0;

To fix that, once you free buf, set the pointer to NULL:

if( recvfrom(sockfd, buf, buflen, 0, (struct sockaddr*)&serv_addr, &slen) == -1){
    close(sockfd);
    free(buf);
    buf = NULL;

There is also an issue where you are potentially reading from buf after it has possibly been free'd. (note the memcpy above.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top