【问题标题】:Suspicious Segmentation Fault using openmp locks使用 openmp 锁的可疑分段错误
【发布时间】:2020-06-13 23:31:25
【问题描述】:

我的程序因分段错误而终止。我将代码简化为:

#include <string>
#include <omp.h>
#include <iostream>

namespace ns { // Holds three strings
    static const std::string A = "a";
    static const std::string B = "b";
    static const std::string C = "c";
}

namespace ns2 {
    // Wraps an ostream and a lock; for example, concurrent access
    // can be implemented this way
    class wrapper { 
    private:
        std::ostream &_stream;
        omp_lock_t _lock;
    public:
        wrapper(std::ostream &stream) : _stream(stream)
        {
            omp_init_lock(&_lock);
        }
        // Segmentation Fault also occurs without destructor
        ~wrapper()
        {
            omp_destroy_lock(&_lock);
        }
    };
    // Wrap stdout
    static wrapper cout(std::cout);
}

namespace ns3 {
    struct somestruct {
        const std::string _0;   
        const std::string _a;
        const std::string _b;
        const std::string _c;
        somestruct(std::string o, std::string a, std::string b, std::string c)
            : _0(o), _a(a), _b(b), _c(c) { }
    };
}

int main(int argc, char *argv[])
{   
    ns3::somestruct cont("0", ns::A, ns::B, ns::C);
    return 0;
}

我在 MacOS 上编译:

系统版本:OS X 10.11.6 (15G22010)
内核版本:达尔文 15.6.0

使用g++-7:

g++-7(自制 GCC 7.5.0_1)7.5.0
版权所有 (C) 2017 Free Software Foundation, Inc.
这是免费软件;查看复制条件的来源。没有
保修单;甚至不是为了适销性或特定用途的适用性。

命令行是 g++-7 file.cpp -O1 -fopenmp

-O2-O3 也会发生分段错误,但 -O0 不会发生分段错误。奇怪的是,它只发生在这台机器上,而我的其他机器和godbolt都没有。

我在可执行文件上运行了valgrind。这是输出:

==54305== Memcheck,一个内存错误检测器
==54305== 版权所有 (C) 2002-2017 和 GNU GPL,由 Julian Seward 等人撰写。
==54305== 使用 Valgrind-3.15.0 和 LibVEX;使用 -h 重新运行以获取版权信息
==54305== 命令:./a.out
==54305==
==54305== 大小为 1 的读取无效
==54305== 在 0x100000906: void std::__cxx11::basic_string, std::allocator >::_M_construct(char const*, char const*, std::forward_iterator_tag) [clone .isra.23] (basic_string.h :338)
==54305== by 0x1000009EC: main (basic_string.h:236)
==54305== 地址 0x4d55545a4d55545a 没有被堆栈、malloc 或(最近)释放
==54305==
==54305== 信号 11 正在从线程 0 的队列中删除

后面是无限循环

==54305== 信号 11 正在从线程 0 的队列中删除

之后我必须使用kill 来停止memcheck,它对Ctrl+C 没有反应。另请参阅 this question 以获取来自 valgrind 的类似回复。但是,这里似乎有不同的原因。

目前我无法使用gdb,因为我必须对其进行代码设计(我认为仅通过终端/ssh 是不可能的)。

另一个有趣的事情是,如果我注释掉 ns3::somestruct cont("0", ns::A, ns::B, ns::C); 行而不是简单地打印

分段错误:11

程序的输出变成了

a.out(54371,0x7fff77d7d000) malloc: *** 对象 0x4d55545a4d55545a 错误:未分配指针被释放
*** 在 malloc_error_break 中设置断点进行调试
中止陷阱:6

我看不出分段错误是从哪里来的。我错过了什么吗?

编辑

我已经设法让gdb 工作。这是输出:

[进程 55870 的新线程 0x1703]
程序收到信号 SIGSEGV,分段错误。
警告:`/private/tmp/gcc@7-20200229-63593-evr5eg/gcc-7.5.0/build/x86_64-apple-darwin15.6.0/libstdc++-v3/src/.libs/compatibility-atomic-c++ 0x.o':无法打开读取符号:没有这样的文件或目录。
[后面还有很多类似的警告]
程序收到信号 SIGSEGV,分段错误。
std::__cxx11::basic_string, std::allocator >::_M_construct (this=0x7fff5fbffb70, __beg=0x4d55545a4d55545a , __end=)
(gdb) 在哪里
#0 std::__cxx11::basic_string, std::allocator >::_M_construct (this=0x7fff5fbffb70, __beg=0x4d55545a4d55545a , __end=)
#1 0x0000000100000a2f 位于 /usr/local/Cellar/gcc@7/7.5.0_1/include/c++/7.5.0/bits/basic_string.h:236 的 main (argc=, argv=)

我还是不明白,为什么会这样。我最近更新了自制软件,从那以后这个“错误”似乎发生了,从那时起这个错误就发生了。关于哪个库可能需要更新或类似的任何想法?

编辑 2

同样,注释掉main 的第一行会解决问题:

a.out(55934,0x7fff77d7d000) malloc: *** 对象 0x4d55545a4d55545a 错误:未分配指针被释放
*** 在 malloc_error_break 中设置断点进行调试

程序收到信号 SIGABRT,已中止。
0x00007fff88204f06 in __pthread_kill () from /usr/lib/system/libsystem_kernel.dylib
(gdb) 在哪里
#0 0x00007fff88204f06 in __pthread_kill () from /usr/lib/system/libsystem_kernel.dylib
#1 0x00007fff8c40d4ec in pthread_kill () from /usr/lib/system/libsystem_pthread.dylib
#2 0x00007fff8b7f06df in abort () from /usr/lib/system/libsystem_c.dylib
#3 0x00007fff88273041 in free () from /usr/lib/system/libsystem_malloc.dylib
#4 0x00007fff8b7f1463 in __cxa_finalize_ranges () from /usr/lib/system/libsystem_c.dylib
#5 0x00007fff8b7f1767 in exit () from /usr/lib/system/libsystem_c.dylib
#6 0x00007fff939de5b4 in start () from /usr/lib/system/libdyld.dylib
#7 0x0000000000000000 在 ?? ()

编辑 3

otool -Lldd 在这台机器上不可用,但根据this discussion 应该是等效的)给出以下输出:

a.out:
/usr/local/opt/gcc@7/lib/gcc/7/libstdc++.6.dylib(兼容版本7.0.0,当前版本7.24.0)
/usr/local/opt/gcc@7/lib/gcc/7/libgomp.1.dylib(兼容版本2.0.0,当前版本2.0.0)
/usr/lib/libSystem.B.dylib(兼容版本 1.0.0,当前版本 1226.10.1)
/usr/local/lib/gcc/7/libgcc_s.1.dylib(兼容版本1.0.0,当前版本1.0.0)

我会在 gcc@9 重新安装后添加它会发生什么,但我记得在之前的安装中,行为应该是相同的。

行为与g++-9 相同。 otool -L 输出显示了 dylib 的版本 9 变体,但 /usr/lib/libSystem.B.dylib 在本例中是相同的。

谁能重现这个错误?

编辑 4

我在更新自制程序之前编译的旧版本的可执行文件上使用了otool -L。它引用了

/usr/local/opt/gcc@7/lib/gcc/7/libstdc++.6.dylib(兼容版本7.0.0,当前版本7.23.0)

而所有其他库都是相同的版本。此外,g++-9 编译的可执行文件还引用了版本 7.24.0。 也许这会导致错误? 如何重新安装这个旧版本的 libstdc++ 来检验这个假设? 我强迫 brew 重新安装 g++ 版本 7.1.0,它使用版本 7.23.0 的 libstdc++。错误仍然存​​在。

【问题讨论】:

  • 您是否使用 GCC-8 和 GCC-9 等较新版本的 GCC 进行了测试? ldd 在生成的可执行文件上的结果是什么?
  • @JérômeRichard 我添加了一些信息。
  • 当你在STL中出现问题时,很可能是header和动态库的版本没有使用相同的版本,一起不兼容。您拥有的版本是可疑的,因为 so 文件指示版本 6 和 otool 版本 7。此外,从 GCC documentation 我们可以看到 GCC 应该使用旧版本(但可能版本 7.23 与 6.xx 兼容版本,虽然这会令人惊讶)。

标签: c++ macos segmentation-fault g++ openmp


【解决方案1】:

在尝试了很多之后,我最终决定将操作系统升级到 macOS Mojave。在我brew reinstalled everything 之后,这解决了问题。 (但是,请注意 valgrind 似乎还不适用于 Mojave。此外,我注意到 gnuplot 等其他软件中的更多问题,程序无法正常启动。)

请注意,brew 警告我尝试在旧 macOS 版本上使用它时可能会出现问题,并且在技术上不再支持它。此外,我更新了 Xcode 和 clang,它们也已经过时了很长时间。

因此,这个问题似乎是由操作系统、brew/clang 和 gnu 编译器之间的某种版本不匹配引起的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-24
    • 1970-01-01
    • 2022-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多