Malloc 在递归函数中崩溃
我目前正在编写 Burrows-Wheeler 变换的实现,它需要对(大)数组进行排序。由于我想并行化递归排序函数的部分代码,因此我决定在堆中分配一些局部变量(使用 malloc()
)以防止堆栈溢出或 - 至少 - make程序优雅地终止。这引发了一系列全新的问题。我将代码精简到核心部分(即导致问题的原因)。
下面的代码编译没有错误。使用 icc 编译时生成的程序工作正常,但使用 gcc 或 tcc 编译时会(随机)崩溃。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
unsigned char *block;
int *indexes, *indexes_copy;
void radixsort(int from, int to, int step)
{
int *occurrences, *first_index_of, i;
if((occurrences = malloc(1024)) == 0)
exit(1);
if((first_index_of = malloc(1024)) == 0)
exit(1);
memset(occurrences, 0, 1024);
for(i = from; i < to; i++)
occurrences[block[indexes[i] + step]]++;
first_index_of[0] = from;
for(i = 0; i < 256; i++)
first_index_of[i + 1] = first_index_of[i] + occurrences[i];
memset(occurrences, 0, 1024);
memcpy(&indexes_copy[from], &indexes[from], 4 * (to - from));
for(i = from; i < to; i++)
indexes[first_index_of[block[indexes_copy[i] + step]] + occurrences[block[indexes_copy[i] + step]]++] = indexes_copy[i];
for(i = 0; i < 256; i++)
if(occurrences[i] > 1)
radixsort(first_index_of[i], first_index_of[i] + occurrences[i], step + 1);
free(occurrences);
free(first_index_of);
}
int main(int argument_count, char *arguments[])
{
int block_length, i;
FILE *input_file = fopen(arguments[1], "rb");
fseek(input_file, 0, SEEK_END);
block_length = ftell(input_file);
rewind(input_file);
block = malloc(block_length);
indexes = malloc(4 * block_length);
indexes_copy = malloc(4 * block_length);
fread(block, 1, block_length, input_file);
for(i = 0; i < block_length; i++)
indexes[i] = i;
radixsort(0, block_length, 0);
exit(0);
}
即使输入是非常小的文本文件(大约 50 字节),程序对于后两个编译器来说也非常不稳定。它的工作概率约为 50%。在其他情况下,当调用 malloc()
时,它会在 radixsort 的第二次或第三次迭代中崩溃。当输入文件较大(大约 1 MiB)时,它总是崩溃。同样在第二次或第三次迭代中...
手动增加堆没有任何好处。不管怎样,都不应该。如果 malloc()
无法分配内存,它应该返回一个 NULL
指针(并且不会崩溃)。
从堆切换回堆栈使程序可以使用任一编译器(只要输入文件足够小)。
那么,我错过了什么/做错了什么?
I'm currently coding an implementation of the Burrows-Wheeler Transform which requires sorting a (large) array. Since I want to parallelize parts of the code of a recursive sort function, I decided to allocate some of the local variables in the heap (using malloc()
) to prevent stack overflows or - at least- make the program die gracefully. That raised a whole new bunch of issues. I stripped the code down to the essential part (i.e., what causes the issues).
The following code compiles without errors. The resulting program works fine when compiled with icc, but it crashes (randomly) when compiled with gcc or tcc.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
unsigned char *block;
int *indexes, *indexes_copy;
void radixsort(int from, int to, int step)
{
int *occurrences, *first_index_of, i;
if((occurrences = malloc(1024)) == 0)
exit(1);
if((first_index_of = malloc(1024)) == 0)
exit(1);
memset(occurrences, 0, 1024);
for(i = from; i < to; i++)
occurrences[block[indexes[i] + step]]++;
first_index_of[0] = from;
for(i = 0; i < 256; i++)
first_index_of[i + 1] = first_index_of[i] + occurrences[i];
memset(occurrences, 0, 1024);
memcpy(&indexes_copy[from], &indexes[from], 4 * (to - from));
for(i = from; i < to; i++)
indexes[first_index_of[block[indexes_copy[i] + step]] + occurrences[block[indexes_copy[i] + step]]++] = indexes_copy[i];
for(i = 0; i < 256; i++)
if(occurrences[i] > 1)
radixsort(first_index_of[i], first_index_of[i] + occurrences[i], step + 1);
free(occurrences);
free(first_index_of);
}
int main(int argument_count, char *arguments[])
{
int block_length, i;
FILE *input_file = fopen(arguments[1], "rb");
fseek(input_file, 0, SEEK_END);
block_length = ftell(input_file);
rewind(input_file);
block = malloc(block_length);
indexes = malloc(4 * block_length);
indexes_copy = malloc(4 * block_length);
fread(block, 1, block_length, input_file);
for(i = 0; i < block_length; i++)
indexes[i] = i;
radixsort(0, block_length, 0);
exit(0);
}
Even when the input is a very small text file (around 50 bytes), the program is very unstable with the latter two compilers. It works with ~50% probability. In the other cases, it crashes in the 2nd or 3rd iteration of radixsort when calling malloc()
. It always crashes when the input file is bigger (around 1 MiB). Also in the 2nd or 3rd iteration...
Manually increasing the heap doesn't do any good. Either way, it shouldn't. If malloc()
can't allocate the memory, it should return a NULL
pointer (and not crash).
Switching back from heap to stack makes the program work with either compiler (as long as the input file is small enough).
So, what am I missing / doing wrong?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
但还有更多问题...
更新(1024 = 4 * 256 似乎只是风格上...)
[i+1] 索引将寻址超出其大小的数组;
But there are more problems ...
UPDATE (the 1024 = 4 * 256 seems merely stylistic ...)
The [i+1] index will address the array beyond its size;