Search code examples
cmemory-managementrealloc

Problems using "realloc" in C


I have code receiving string data from a socket which crashes on the first iteration:

int size_data = 1024*sizeof(char);              
char *data = malloc(size_data);
char *data_aux;
int br_aux=0;
int *nptr;

memset(&data[0], 0, size_data);
int br = recv(sockdata, data, size_data, 0);
data_aux = malloc(br);
while (br>0) {
  br_aux = br_aux + br;
  strcat(data_aux, data);
  br = recv(sockdata,data, size_data, 0);
  if (br > 0) {
    nptr = (int *) realloc(data_aux, br+br_aux);
  }
}
free(data);
printf("%s", data_aux);
free(data_aux);

Nothing so complicated, but however I get an error:

* glibc detected ./clientFTP: free(): invalid next size (normal): 0x00000000061d6420 ** ======= Backtrace: ========= /lib64/libc.so.6[0x366be7247f] /lib64/libc.so.6(cfree+0x4b)[0x366be728db] ./clientFTP[0x401e39] /lib64/libc.so.6(__libc_start_main+0xf4)[0x366be1d9b4] ./clientFTP[0x400b89] ======= Memory map: ======== 00400000-00403000 r-xp 00000000 fd:00 5396214 /home/alumno/FTP/clientFTP 00602000-00603000 rw-p 00002000 fd:00 5396214
/home/alumno/FTP/clientFTP 061d6000-061f7000 rw-p 061d6000 00:00 0
[heap] 366ba00000-366ba1c000 r-xp 00000000 fd:00 1994999
/lib64/ld-2.5.so 366bc1c000-366bc1d000 r--p 0001c000 fd:00 1994999
/lib64/ld-2.5.so 366bc1d000-366bc1e000 rw-p 0001d000 fd:00 1994999
/lib64/ld-2.5.so 366be00000-366bf4e000 r-xp 00000000 fd:00 1995001
/lib64/libc-2.5.so 366bf4e000-366c14e000 ---p 0014e000 fd:00 1995001
/lib64/libc-2.5.so 366c14e000-366c152000 r--p 0014e000 fd:00 1995001
/lib64/libc-2.5.so 366c152000-366c153000 rw-p 00152000 fd:00 1995001
/lib64/libc-2.5.so 366c153000-366c158000 rw-p 366c153000 00:00 0 3672200000-367220d000 r-xp 00000000 fd:00 1995011
/lib64/libgcc_s-4.1.2-20080825.so.1 367220d000-367240d000 ---p 0000d000 fd:00 1995011
/lib64/libgcc_s-4.1.2-20080825.so.1 367240d000-367240e000 rw-p 0000d000 fd:00 1995011
/lib64/libgcc_s-4.1.2-20080825.so.1 2b5cdf8d9000-2b5cdf8dd000 rw-p 2b5cdf8d9000 00:00 0 2b5cdf8f6000-2b5cdf8f7000 rw-p 2b5cdf8f6000 00:00 0 7fffae47e000-7fffae493000 rw-p 7ffffffe9000 00:00 0
[stack] 7fffae5fc000-7fffae600000 r-xp 7fffae5fc000 00:00 0
[vdso] ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00 0
[vsyscall] Aborted


Solution

  • There are two different problems.

    First, the line

    nptr = (int *)realloc(data_aux,(br+br_aux));
    

    does three things:

    1. It tries to allocate br + br_aux bytes.
    2. It may release the memory that data_aux points to.
    3. It points nptr to the address of the newly-allocated memory.

    But the code continues to use data_aux as if it still points to the new memory.

    Second, since recv() returns the number of bytes that were received, you should use that information to append data to the buffer:

    while (br > 0) {
      memcpy(data_aux + br_aux, data, br);
      br_aux += br;
      br = recv(sockdata, data, size_data, 0);
      if (br > 0) {
        nptr = (int *) realloc(data_aux, br + br_aux);
        if (nptr == NULL) {
          // ERROR
        }
        data_aux = nptr;
      }
    }
    

    The problem with recv() in combination with any of the string operations (like strcat()) is that recv() can return binary data. If that data happens to contain a zero byte, the string functions will assume it's the end of the data and behave in ways you neither expect nor want.

    There's actually a third problem, which is that none of the return values is checked for errors. Always check for errors instead of assuming that memory is valid, or that socked communication has succeeded.