为什么使用 MPI_Bcast 和 -O3 编译器标志会出现堆栈粉碎错误,但没有 -O3 一切正常?

Why do I get a stack smashing error using MPI_Bcast and -O3 compiler flag, but everything works without -O3?

我是 MPI 的新手,如果这很简单,请见谅。

我有一两个月前的一些代码运行良好,但我决定回去修改它。 (它是我刚开始时写的,它不是性能关键部分。)代码基本上在一个进程上生成一个随机图,然后与所有其他进程共享结果。婴儿第一步版本的摘录如下:

unsigned int *graph;

if (commrank == 0) {
    graph = gengraph(params); //allocates graph memory in function
    if (commsize > 1) {
        for (int k=1; k<commsize; k++) 
            MPI_Send(graph, n*n, MPI_UNSIGNED, k, 0, MPI_COMM_WORLD);
    }
} else {
    MPI_Status recvStatus;
    graph = malloc(sizeof(unsigned int)*n*n);
    MPI_Recv(graph, n*n, MPI_UNSIGNED, 0, 0, MPI_COMM_WORLD, &recvStatus);
}

虽然这显然很天真,但在我选择返回并以我认为合适的方式进行操作之前,这在一段时间内效果很好:

if (commrank == 0) {
    graph = gengraph(params);
    MPI_Bcast(graph, n*n, MPI_UNSIGNED, 0, MPI_COMM_WORLD);
} else {
    graph = malloc(sizeof(unsigned int)*n*n);
    MPI_Bcast(graph, n*n, MPI_UNSIGNED, 0, MPI_COMM_WORLD);
}

问题是,当我使用 -O3 优化编译时,我在第二个版本中不断遇到 "stack smashing" 错误,尽管在未优化编译时它工作正常。注意,我已经多次检查了图分配函数并进行了调试,似乎没有问题。我还调试了第二个版本,它似乎工作正常。当我尝试释放图形内存时,稍后会发生崩溃。 (请注意,这不是双重释放错误,而且,它在天真的实现中工作正常并且已经有一段时间了。)

最后一个问题:如果我没有使用 recvStatus 变量,而是使用 MPI_STATUS_IGNORE第一个 版本也会失败。而且,同样,这仅在 -O3 时失败。

如有任何想法,我们将不胜感激。如果有任何帮助,我在 gcc 7.5.0 之上使用 mpicc,但我想我在做一些愚蠢的事情而不是遇到编译器问题。

根据@hristo-iliev 的建议,我将 mpicc 编译器更改为 Clang 并使用了 Address Sanitizer,并在随后的 MPI 调用中发现错误(计数大小错误的 recv)。这导致了未定义的行为。值得注意的是,地址清理器非常清楚地指出了错误的位置,而 valgrind 只给出了相当不透明的指示,表明 MPI 中正在发生某些事情(好吧,它总是这样)。

为此向 Whosebug 社区致歉,因为上面的代码不是罪魁祸首(并不完全令人惊讶)。由于草率,这只是一些标准的未定义行为。