free() 在 char 数组上崩溃,但前提是该数组恰好包含 7 个元素
free() crashing on char array, but only if the array holds exactly 7 elements
我有一个简单的 C 程序,它应该从另一个程序、UNIX 命名管道读取一条消息并将其显示给用户。
程序执行此操作的方式如下:
- 从管道读取传入消息大小
- 为传入消息分配足够的内存,并为空终止符分配另一个字节
- 将传入数据读取到分配的内存
- 附加空终止符和 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)
是指针的大小,可能和整数的大小不一样
我有一个简单的 C 程序,它应该从另一个程序、UNIX 命名管道读取一条消息并将其显示给用户。
程序执行此操作的方式如下:
- 从管道读取传入消息大小
- 为传入消息分配足够的内存,并为空终止符分配另一个字节
- 将传入数据读取到分配的内存
- 附加空终止符和 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)
是指针的大小,可能和整数的大小不一样