使用 openmp 锁的可疑分段错误

Suspicious Segmentation Fault using openmp locks

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

#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 上编译:

System Version: OS X 10.11.6 (15G22010)
Kernel Version: Darwin 15.6.0

使用 g++-7:

g++-7 (Homebrew GCC 7.5.0_1) 7.5.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

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

-O2-O3 也会出现分段错误,但不会出现 -O0。 St运行gely,它只发生在这台机器和我其他机器的 none 或 godbolt.

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

==54305== Memcheck, a memory error detector
==54305== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==54305== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==54305== Command: ./a.out
==54305==
==54305== Invalid read of size 1
==54305== at 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== Address 0x4d55545a4d55545a is not stack'd, malloc'd or (recently) free'd
==54305==
==54305== Signal 11 being dropped from thread 0's queue

接着是

的无限循环

==54305== Signal 11 being dropped from thread 0's queue

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

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

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

Segmentation fault: 11

程序的输出变为

a.out(54371,0x7fff77d7d000) malloc: *** error for object 0x4d55545a4d55545a: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

我看不出分段错误从何而来。我错过了什么吗?

编辑

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

[New Thread 0x1703 of process 55870]
Program received signal SIGSEGV, Segmentation fault.
warning: `/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': can't open to read symbols: No such file or directory.
[Followed by a lot more warnings like that]
Program received signal SIGSEGV, Segmentation fault.
std::__cxx11::basic_string, std::allocator >::_M_construct (this=0x7fff5fbffb70, __beg=0x4d55545a4d55545a , __end=)
(gdb) where
#0 std::__cxx11::basic_string, std::allocator >::_M_construct (this=0x7fff5fbffb70, __beg=0x4d55545a4d55545a , __end=)
#1 0x0000000100000a2f in main (argc=, argv=) at /usr/local/Cellar/gcc@7/7.5.0_1/include/c++/7.5.0/bits/basic_string.h:236

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

编辑 2

同样,注释掉 main 的第一行移动了问题:

a.out(55934,0x7fff77d7d000) malloc: *** error for object 0x4d55545a4d55545a: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug

Program received signal SIGABRT, Aborted.
0x00007fff88204f06 in __pthread_kill () from /usr/lib/system/libsystem_kernel.dylib
(gdb) where
#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 in ?? ()

编辑 3

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

a.out:
/usr/local/opt/gcc@7/lib/gcc/7/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.24.0)
/usr/local/opt/gcc@7/lib/gcc/7/libgomp.1.dylib (compatibility version 2.0.0, current version 2.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)
/usr/local/lib/gcc/7/libgcc_s.1.dylib (compatibility version 1.0.0, current version 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 (compatibility version 7.0.0, current version 7.23.0)

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

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

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

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