在C中使用“realloc”的问题

时间:2012-05-16 01:43:36

标签: c memory-management realloc

我有代码从第一次迭代崩溃的套接字接收字符串数据:

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);

没有那么复杂,但是我得到了一个错误:

  

* glibc检测到 ./clientFTP:free():无效的下一个尺寸(正常):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]   =======内存映射:======== 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
  [堆] 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]已中止

5 个答案:

答案 0 :(得分:2)

有两个不同的问题。

首先,行

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

做了三件事:

  1. 尝试分配br + br_aux个字节。
  2. 它可能释放data_aux指向的内存。
  3. 它将nptr指向新分配的内存的地址。
  4. 但是代码继续使用data_aux,好像它仍然指向新内存。

    其次,由于recv()返回已接收的字节数,您应该使用该信息将数据附加到缓冲区:

    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;
      }
    }
    

    recv()与任何字符串操作(如strcat())结合使用的问题是recv()可以返回二进制数据。如果该数据恰好包含零字节,则字符串函数将假定它是数据的结尾,并以您既不期望也不想要的方式运行。

    实际上存在第三个问题,即没有检查任何返回值是否有错误。 始终检查错误,而不是假设内存有效,或者socked通信成功。

答案 1 :(得分:1)

代码中存在许多问题,但我会解决大问题:

  1. 您正在分配内存并假设它已准备就绪:

    data_aux = malloc(br);
    ...
    strcat(data_aux, data); /* <- who said data_aux isn't garbage? */
    
  2. 您应该考虑realloc has moved your data or when the call itself failsdata_aux不够大的情况:

      

    成功完成且大小不等于0时,realloc()返回指向(可能已移动)分配空间的指针。如果size为0,则返回空指针或可成功传递给free()的唯一指针。如果没有足够的可用内存,realloc()将返回空指针并将errno设置为ENOMEM

    data_aux = realloc(data_aux, br + br_aux); /* reassign data_aux */
    
  3. 您没有检查任何返回值。一个大的不是在用它分配内存之前检查recv()的结果:

    br = recv(...);
    ...
    data_aux = malloc(br); /* -1 as a size is large in unsigned speak */
    
  4. 您正在对可能甚至不包含char的数据使用ASCIIZ字符串函数。使用memcpy代替strcatstrncat

答案 2 :(得分:0)

呃 - 是你从socket null接收的字符串?

建议:

  1. 确保在发送之前在邮件中包含空字节

  2. 使用strncat()

  3. 如有必要,Null自行终止缓冲区

  4. PS: 我猜你在“strcat(data_aux)”中占用了缓冲区,这无意中破坏了“数据”和“data_aux”。

答案 3 :(得分:0)

如果realloc()成功,则输入内存块不再有效,返回的指针指向新的内存块。如果realloc()失败,则输入内存块仍然有效。您将返回的指针分配给一个根本不用于任何内容的nptr变量,并且您永远不会更新data_aux变量以指向重新分配的内存。当您致电free()以免费data_aux时,如果预先调用了realloc()并且成功了,那么您将释放错误的指针,这可能导致您看到的崩溃。

改变这个:

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

改为:

nptr = (char*)realloc(data_aux, br_aux + br); 
if (!nptr)
{
    ... error handling ...
    break;
}
data_aux = nptr;

话虽如此,你应该将整个逻辑重写为更像下面的内容。无需在循环中多次调用recv()

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

char *data = malloc(size_data);  
if (data)
{
    int br = recv(sockdata, data, size_data, 0);
    while (br > 0)
    {  
        nptr = (char*) realloc(data_aux, br_aux + br);
        if (!nptr)
            break;

        data_aux = nptr;
        memcpy(&data_aux[br_aux], data, br);  
        br_aux = br_aux + br;  
    }  

    free(data);  
}

printf("%.*s", br_aux, data_aux);  
free(data_aux);  

为了进一步简化,请将data缓冲区放在堆栈上:

char* data_aux = NULL;
int br_aux = 0;  

char data[1024];
char *nptr;  

int br = recv(sockdata, data, sizeof(data), 0);
while (br > 0)
{  
    nptr = (char*) realloc(data_aux, br_aux + br);
    if (!nptr)
        break;

    data_aux = nptr;
    memcpy(&data_aux[br_aux], data, br);  
    br_aux = br_aux + br;  
}  

printf("%.*s", br_aux, data_aux);  
free(data_aux);  

答案 4 :(得分:0)

data_aux = malloc(br);   //data_aux may not filled with zero
//data_aux[0] = '\o';

while (br>0)
{
    br_aux = br_aux + br;  
    strcat(data_aux,data); //this may casue overflow, data may not end with '\0'
    br = recv(sockdata,data, size_data,0); 
    if(br>0)
    {
        //need check nptr is NULL? and size is (br + br_aux + 1), '\0' need one byte
        //nptr = (char*)realloc(data_aux,(br + br_aux + 1)); 
        nptr = (int *)realloc(data_aux,(br+br_aux)); 
        // if (nptr != NULL)
        //     data_aux = nptr;
        // else
        //     Error handling
    }
}