【问题标题】:MPI segfaults when passing simple struct to function将简单结构传递给函数时 MPI 段错误
【发布时间】:2021-10-07 21:57:35
【问题描述】:

我正在使用 MPI 在 C 中构建蒙特卡罗模拟,但在使用结构读取文件时遇到了一个奇怪的错误。我在下面的简单代码中复制了这个问题。此示例代码以与更大的模拟相同的方式失败。下面是 main.c 的内容。 readme.txt 的内容只是一小行文本。

#include <mpi.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct test_struct {
        char * filename;
} test_struct;


int read(struct test_struct * obj){
        FILE * file = fopen(obj->filename, "r");
        char buf[512];
        if (file == NULL) return -1;
        else {
                fgets(buf, sizeof(buf), file);
                printf("%s\n", buf);
        }
        fclose(file);
        return 0;

}

int main() {

        MPI_Init(NULL, NULL);

        int world_rank;
        MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
        int world_size;
        MPI_Comm_size(MPI_COMM_WORLD, &world_size);

        struct test_struct obj;

        obj.filename = (char *) malloc(256*sizeof(char));
        strcpy(obj.filename, "readme.txt");
        printf("%s\n", obj.filename);
        read(&obj);

        free(obj.filename);

        return 0;
}

我使用这个简单的命令mpicc -g main.c 进行编译。当我运行可执行文件时,我收到以下错误消息。

→ ./a.out
[lap-johnson:00190] *** Process received signal ***
[lap-johnson:00190] Signal: Segmentation fault (11)
[lap-johnson:00190] Signal code: Address not mapped (1)
[lap-johnson:00190] Failing at address: 0x7
[lap-johnson:00190] [ 0] /lib/x86_64-linux-gnu/libpthread.so.0(+0x12730)[0x7f2023741730]
[lap-johnson:00190] [ 1] ./a.out(read+0x19)[0x7f20238a41ae]
[lap-johnson:00190] [ 2] /usr/lib/x86_64-linux-gnu/openmpi/lib/openmpi3/mca_ess_singleton.so(+0x2e77)[0x7f20225e2e77]
[lap-johnson:00190] [ 3] /usr/lib/x86_64-linux-gnu/libopen-rte.so.40(orte_init+0x29a)[0x7f20234aa11a]
[lap-johnson:00190] [ 4] /usr/lib/x86_64-linux-gnu/libmpi.so.40(ompi_mpi_init+0x252)[0x7f202379be62]
[lap-johnson:00190] [ 5] /usr/lib/x86_64-linux-gnu/libmpi.so.40(MPI_Init+0xa9)[0x7f20237ca1b9]
[lap-johnson:00190] [ 6] ./a.out(+0x1211)[0x7f20238a4211]
[lap-johnson:00190] [ 7] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xeb)[0x7f202358409b]
[lap-johnson:00190] [ 8] ./a.out(+0x10da)[0x7f20238a40da]
[lap-johnson:00190] *** End of error message ***
[1]    190 segmentation fault (core dumped)  ./a.out

我尝试使用 gdb 查看错误的原因。它表示objtest_struct 的实例,位于内存地址 0x7。我认为程序段错误是因为它试图读取这个无效的地址。 gdb 输出如下。

→ gdb ./a.out
GNU gdb (Debian 8.2.1-2+b3) 8.2.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...done.
(gdb) run
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[Detaching after fork from child process 257]

Program received signal SIGSEGV, Segmentation fault.
0x00000000080011be in read (obj=0x7) at main.c:11
11              FILE * file = fopen(obj->filename, "r");
(gdb) print obj
$1 = (struct test_struct *) 0x7
(gdb) print obj->filename
Cannot access memory at address 0x7

为什么read 函数会看到内存地址 0x7 处的结构?我可能在字符串操作方面做错了(或不标准)。但我不知道如何解决这个问题。请注意,这可以在 gcc 中完美编译和运行(当然,如果我删除了 MPI 的东西)。

我确实听说过 MPI 不喜欢将指针作为成员的结构。但我认为那是在发送和接收的背景下。对此问题的任何帮助表示赞赏。我对 MPI 很陌生。

我在 Linux 的 Windows 子系统 (4.4.0-19041-Microsoft) 内的 Debian 上运行 Open MPI 版本 3.1.3。我已确认在使用 Open MPI 版本 2.1.1 的自定义构建的 Debian Linux 机器上发生了同样的问题。

【问题讨论】:

  • 要做的第一件事:检查fopen 是否失败。如果 fopen 失败,它会返回 NULL 并且对 NULL FILE 指针执行文件操作是未定义的行为,在这种情况下,大部分时间都表现为段错误。
  • 1.为什么我们看不到您的printf 的输出,无论是在正常运行还是在 gdb 运行中? 2.文件操作与MPI无关。删除所有 MPI 调用,看看程序是否仍然崩溃。无论如何,您都在按顺序运行/调试它。
  • @TimJohnson edit 问题并将您的新代码放在那里
  • @VictorEijkhout 我删除了 MPI 调用,程序没有崩溃。当我添加 MPI_Init 函数时它崩溃了。
  • 似乎read 函数是在MPI_Init 启动某些东西而不是在您期望的行中调用的!!!如果您将read 重命名为xread,如果文件无效或不存在,则会出现其他类型的错误...我使用 GDB 看到这一点,我建议您使用 GDB 来了解您遇到的问题。

标签: c segmentation-fault mpi


【解决方案1】:

read()libC 的子例程,您不应重新定义它。相反,只需在您的代码中重命名此函数即可。

Open MPI 从libC 调用read(),而是调用了您的子例程,因此出现了奇怪的堆栈跟踪。

【讨论】:

    猜你喜欢
    • 2017-02-26
    • 1970-01-01
    • 2012-10-15
    • 2012-05-09
    • 1970-01-01
    • 2022-01-11
    相关资源
    最近更新 更多