free() 在 char 数组上崩溃,但前提是该数组恰好包含 7 个元素

free() crashing on char array, but only if the array holds exactly 7 elements

我有一个简单的 C 程序,它应该从另一个程序、UNIX 命名管道读取一条消息并将其显示给用户。

程序执行此操作的方式如下:

  1. 从管道读取传入消息大小
  2. 为传入消息分配足够的内存,并为空终止符分配另一个字节
  3. 将传入数据读取到分配的内存
  4. 附加空终止符和 returns

代码如下:

void* ReceiveFromPipe(char* Pipe, int* StuffSize){
    printf("Opening pipe\n");
    int FD = open(Pipe,O_RDONLY);
    printf("Pipe opened from the write side\n");
    read(FD,StuffSize,sizeof(StuffSize));
    printf("Incoming message size : %d\n",*StuffSize);
    void* StuffPointer = calloc((*StuffSize) + 1,1);//allocate stuffsize bytes
    printf("Allocated memory for stuff\n");
    read(FD,StuffPointer,*StuffSize);
    printf("Read stuff from pipe\n");
    close(FD);
    printf("Closed pipe\n");
    ((int*)StuffPointer)[*StuffSize] = 0x00;
    return StuffPointer;
}

而main函数中的代码是一个简单的免读循环,像这样:

int main(void){
    char* message;
    int msgSize = -1;
    while(1){
        message = (char*)ReceiveFromPipe("./PSender0",&msgSize);
        printf("Got :: %s\n",message);
        fflush(stdout);
        free(message);
    }
}

这适用于任何类型的消息,除非该消息恰好有 6 个字节(7 个带有附加的空终止符)。例如,带有 "HelloWorld!" 消息的确切程序将输出:

Opening pipe
Pipe opened from the write side
Incoming message size : 11
Allocated memory for stuff
Read stuff from pipe
Closed pipe
Got :: HelloWorld!
Opening pipe

这是预期的行为,但是对于消息 123456,输出变为

Opening pipe
Pipe opened from the write side
Incoming message size : 6
Allocated memory for stuff
Read stuff from pipe
Closed pipe
Got :: 123456
*** Error in `./Receiver': free(): invalid next size (fast): 0x0000008869995420 ***
======= Backtrace: =========
/usr/lib/libc.so.6(+0x72bdd)[0x7f12da646bdd]
/usr/lib/libc.so.6(+0x792ec)[0x7f12da64d2ec]
/usr/lib/libc.so.6(+0x7a6d1)[0x7f12da64e6d1]
./Receiver(+0xb13)[0x8867c07b13]
/usr/lib/libc.so.6(__libc_start_main+0xea)[0x7f12da5f44ca]
./Receiver(+0x9ba)[0x8867c079ba]
======= Memory map: ========
8867c07000-8867c09000 r-xp 00000000 08:05 6030989                        /home/andre/EI/SO/PipesTest/Receiver
8867e08000-8867e09000 r--p 00001000 08:05 6030989                        /home/andre/EI/SO/PipesTest/Receiver
8867e09000-8867e0a000 rw-p 00002000 08:05 6030989                        /home/andre/EI/SO/PipesTest/Receiver
8869995000-88699b6000 rw-p 00000000 00:00 0                              [heap]
7f12d4000000-7f12d4021000 rw-p 00000000 00:00 0
7f12d4021000-7f12d8000000 ---p 00000000 00:00 0
7f12da3bd000-7f12da3d3000 r-xp 00000000 08:02 545366                     /usr/lib/libgcc_s.so.1
7f12da3d3000-7f12da5d2000 ---p 00016000 08:02 545366                     /usr/lib/libgcc_s.so.1
7f12da5d2000-7f12da5d3000 r--p 00015000 08:02 545366                     /usr/lib/libgcc_s.so.1
7f12da5d3000-7f12da5d4000 rw-p 00016000 08:02 545366                     /usr/lib/libgcc_s.so.1
7f12da5d4000-7f12da771000 r-xp 00000000 08:02 526947                     /usr/lib/libc-2.25.so
7f12da771000-7f12da970000 ---p 0019d000 08:02 526947                     /usr/lib/libc-2.25.so
7f12da970000-7f12da974000 r--p 0019c000 08:02 526947                     /usr/lib/libc-2.25.so
7f12da974000-7f12da976000 rw-p 001a0000 08:02 526947                     /usr/lib/libc-2.25.so
7f12da976000-7f12da97a000 rw-p 00000000 00:00 0
7f12da97a000-7f12da99d000 r-xp 00000000 08:02 526937                     /usr/lib/ld-2.25.so
7f12dab34000-7f12dab36000 rw-p 00000000 00:00 0
7f12dab9c000-7f12dab9d000 rw-p 00000000 00:00 0
7f12dab9d000-7f12dab9e000 r--p 00023000 08:02 526937                     /usr/lib/ld-2.25.so
7f12dab9e000-7f12dab9f000 rw-p 00024000 08:02 526937                     /usr/lib/ld-2.25.so
7f12dab9f000-7f12daba0000 rw-p 00000000 00:00 0
7ffe4c462000-7ffe4c483000 rw-p 00000000 00:00 0                          [stack]
7ffe4c495000-7ffe4c498000 r--p 00000000 00:00 0                          [vvar]
7ffe4c498000-7ffe4c49a000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted (core dumped)

我真的找不到这段代码中的问题,甚至无法想象为什么它只在 6 个字符的消息上失败,不胜感激任何帮助

这一行:

((int*)StuffPointer)[*StuffSize] = 0x00;

您将 StuffPointer 转换为整数指针,因此数组访问将使用 sizeof int 来计算写入 0 整数值的位置。

这将在您的数组边界之外写入,这可能会导致您遇到的问题。

编辑:要解决此问题,您可以转换为 (char *),或将 StuffPointer 设为 char *

还有

read(FD,StuffSize,sizeof(StuffSize));

应该是

read(FD,StuffSize,sizeof(*StuffSize));

因为sizeof(StuffSize)是指针的大小,可能和整数的大小不一样