【问题标题】:Problems using "realloc" in C在 C 中使用“realloc”的问题
【发布时间】:2012-05-23 13:38:29
【问题描述】:

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

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(): invalid next size (normal): 0x00000000061d6420 ** ======= 回溯:========= /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
[堆栈] 7fffae5fc000-7fffae600000 r-xp 7fffae5fc000 00:00 0
[vdso] ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00 0
[vsyscall] 中止

【问题讨论】:

    标签: c memory-management realloc


    【解决方案1】:

    有两个不同的问题。

    首先是行

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

    做三件事:

    1. 它尝试分配br + br_aux 字节。
    2. 可能会释放data_aux指向的内存。
    3. 它将nptr指向新分配的内存地址。

    但是代码继续使用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 通信已成功。

    【讨论】:

    • 非常感谢它成功了!!!但我只是在这一行更改了您的代码: nptr = (int *) realloc(data_aux, br + br_aux);对于这个: data_aux = (char *) realloc(data_aux, br + br_aux);你能解释一下为什么 memcpy 工作而不是 strcat 吗?谢谢
    • 很高兴它工作,但你真的应该检查错误。如果发生错误,realloc() 可以返回NULL,这将导致程序崩溃。您需要memcpy() 而不是strcat(),因为字符串函数会在遇到 0(空字符)字节时停止。 memxxx() 函数采用显式长度参数。
    • 如果我想接收其他类型的文件,如 zip 文件,我可以使用什么(我试过但没有用)
    • 说“它没有用”太含糊了。发生了什么?上面的 sn-p 应该适用于任何类型的文件,除非您的内存不足......这就是为什么您需要检查返回值是否有错误。 :-)
    • 显然我在 br 中多次收到 1024 字节(因为文件很大),但我不知道为什么它不复制套接字接收到的信息。结果是一个 5 字节的数据,而原始文件是 19xxx 字节。我可以检查什么?
    【解决方案2】:

    代码中有很多问题,但我会解决大问题:

    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. 您正在对可能不包含 chars 的数据使用 ASCIIZ 字符串函数。使用memcpy 而不是strcatstrncat

    【讨论】:

    • 为了澄清第二点,您应该将 realloc 的返回值分配给 data_aux,而不是分配给 nptr。 (并且您应该将返回值转换为 char*。)
    • 这个答案错过了两个的大问题。没有检查空字符,并且指针永远不会调整为指向重新分配的内存。调用realloc() 并继续使用原始指针是永远可接受的。
    • @AdamLiss:我会澄清“准备使用”并添加更多大的。
    • 非常感谢你是对的!正如用户 Adam Liss 建议的那样,我使用 memcpy 而不是 strcat,我想在包含垃圾的情况下初始化 data_aux 的信息......不是吗?
    • @JoeLewis:您只关心该缓冲区的大小是否与recv 接收的数据大小不同。如果这是 ASCIIZ 字符串数据,这意味着您需要确保它是 NUL 终止或将其复制到另一个适当大小的字符缓冲区中。
    【解决方案3】:

    呃 - 你从套接字接收到的字符串是空终止的吗?

    建议:

    1. 确保在发送前在消息中包含空字节

    2. 使用 strncat()

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

    PS: 我猜你正在超出“strcat(data_aux)”中的缓冲区,这会无意中破坏“data”和“data_aux”。

    【讨论】:

    • 我看不出这如何解决我的问题,连接应该可以与 strcat 一起正常工作,并且从套接字接收的字符串不为空,因为我使用了 br 变量。
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:
      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
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-09
        • 2011-05-04
        • 1970-01-01
        • 2013-04-21
        • 2021-10-31
        • 1970-01-01
        相关资源
        最近更新 更多