代码之家  ›  专栏  ›  技术社区  ›  LoneWanderer

PY3之间的C++ DLL行为不同。6和py3。8:Python3.6中的SIGSEGV“\uuu gnu\u cxx::\uu交换和添加”。6.

  •  0
  • LoneWanderer  · 技术社区  · 4 年前

    我有一个项目运行在Python3.8x64Windows上,有一个anaconda环境。

    它使用了一个内部C++ +dll x64,使用了CyType的Python包装(C++代码由于各种原因不能共享;最重要的原因是我自己不能访问99%的代码)。 该项目在Python3.8x64上运行良好。

    主C++ DLL入口点为JSON文件获取一个字符串路径进行初始化。

    class RedactedName:
    
        def __init__(some_args): # redacted
            # some code
            self.dll = ctypes.CDLL(self.dll_path)
            self.dll.load_config_file.argtypes = [ctypes.c_char_p]
            self.dll.load_config_file.restype = ctypes.c_bool
            # some code
    
        def load_config_file(self, file_path: str) -> bool:
            self.conf_file_path = file_path # path of a JSON file, the C++ will load it
            s = ctypes.c_char_p(file_path.encode('utf-8'))
            b = self.dll.load_config_file(s) # <-- SEG FAULT HERE with py3.6.6 only. ok with py3.8
            return bool(b)
    

    bool load_config_file(/* in */ const char * input_json) {
        json conf;
        const std::string & json_file_path_str(input_json);
        REDACTED_FUNCTION_CALL_A(/* in */ json_file_path_str, /* out */ conf); // <-- seg fault in here, depending on python version, see GDB call stack
        // other stuff
        return true; // no joke
    }
    

    使用Python 3.6。6 x64,C++调用 self.dll.load_config_file 进入 SIGSEGV C++ DLL调用堆栈看起来像这样(幸运地,DLL包含一些符号)。

    # (with python breakpoint right before DLL load)
    $ attach <ptyhon process PID>
    $ catch load mylibname
    $ catch throw
    $ c 
    # now, resume python execution
    # when gdb breaks on dll load, add breakpoint
    $ b load_config_file
    

    (gdb) n
    Single stepping until exit from function
     
     
     
     _ZN3REDACTED5REDACTED8REDACTED4REDACTEDKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERN8nlohmann10basic_jsonISt3mapSt6vectorS7_bxydSaNSA_14adl_serializerEEE,
        which has no line number information.
    
        Thread 1 received signal SIGSEGV, Segmentation fault.
        0x000000006fcd2194 in __gnu_cxx::__exchange_and_add (__val=-1, __mem=0x0) at /it/sbx/20.1/x86_64-windows/gcc/build/x86_64-pc-mingw32/libstdc++-v3/include/ext/atomicity.h:82
        82      /it/sbx/20.1/x86_64-windows/gcc/build/x86_64-pc-mingw32/libstdc++-v3/include/ext/atomicity.h: No such file or directory.
    

    #0  0x000000006fcd2194 in __gnu_cxx::__exchange_and_add (__val=-1, __mem=0x0) at /it/sbx/20.1/x86_64-windows/gcc/build/x86_64-pc-mingw32/libstdc++-v3/include/ext/atomicity.h:82
    
    #1  __gnu_cxx::__exchange_and_add_dispatch (__val=-1, __mem=0x0) at /it/sbx/20.1/x86_64-windows/gcc/build/x86_64-pc-mingw32/libstdc++-v3/include/ext/atomicity.h:82
    
    #2  __gnu_cxx::__exchange_and_add_dispatch (__val=-1, __mem=0x0) at /it/sbx/20.1/x86_64-windows/gcc/build/x86_64-pc-mingw32/libstdc++-v3/include/ext/atomicity.h:78
    
    #3  std::locale::_Impl::_M_remove_reference (this=0x0) at /it/sbx/20.1/x86_64-windows/gcc/build/x86_64-pc-mingw32/libstdc++-v3/include/bits/locale_classes.h:564
    
    #4  std::locale::operator= (this=this@entry=0xbc8f3ecf50, __other=
          @0xbc8f3ec9f8: {static none = 0, static ctype = 1, static numeric = 2, static collate = 4, static time = 8, static monetary = 16, static messages = 32, static all = 63, _M_impl = 0x6fcfc6a0 <(anonymous namespace)::c_locale_impl>, static _S_classic = 0x6fcfc6a0 <(anonymous namespace)::c_locale_impl>, static _S_global = 0x6fcfc6a0 <(anonymous namespace)::c_locale_impl>, static _S_categories = 0x6fd06aa0 <__gnu_cxx::category_names>, static _S_once = {done = 1, started = 0}, static _S_twinned_facets = 0x6fd09140 <std::locale::_S_twinned_facets>}) at ../../../../../src/libstdc++-v3/src/c++98/locale.cc:116
    
    #5  0x000000006fce906c in std::ios_base::_M_init (this=this@entry=0xbc8f3ece80) at ../../../../../src/libstdc++-v3/src/c++98/ios_locale.cc:44
    
    #6  0x000000006fceaf91 in std::basic_ios<char, std::char_traits<char> >::init (this=0xbc8f3ece80, __sb=0x0) at /it/sbx/20.1/x86_64-windows/gcc/build/x86_64-pc-mingw32/libstdc++-v3/include/bits/basic_ios.tcc:126
    
    #7  0x000000006ce0b7fb in REDACTED_FUNCTION_CALL_A(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long long, unsigned long long, double, std::allocator, nlohmann::adl_serializer>&) ()
       from C:\Users\<redacted>/<redacted>_lib.dll
    
    #8  0x000000006cdc15c6 in load_config_file (input_json=0x27eee2877a0 "C:\\Users\\<a_valid_path_to_avalid_json_file>") at <redacted>
    
    #9  0x0000000062880943 in _ctypes!DllCanUnloadNow () from C:\Program Files\Python36\DLLs\_ctypes.pyd
    

    其他信息:

    • python调用完全是顺序的,没有线程,因此 s 变量不能在结束前进行垃圾回收 自己dll。加载配置文件
    • C++ DLL没有被重新编译。它与Py3中的完全相同。8环境。
    • C++ DLL依赖于 libwinpthread-1.dll libgcc_s_seh-1.dll libstdc++-6.dll
    • DLL是用GNAT PRO构建的 g++ (GCC) 8.3.1 20190923 (for GNAT Pro 20.1)
    • DLL链接指令包含“-static libgcc”

    任何关于为什么py3的线索。6.6给出了这个奇怪的cpp调用堆栈&SIGSEGV和py3。8不是吗?

    如果是py3。8版本不起作用,我想它是 undefined reference to `__gnu_cxx::__exchange_and_add(int*, int)' . 但事实并非如此。。。

    • std::basic_ios<char, std::char_traits<char> >::init 似乎与流缓冲区初始化有关。可能是std输出流的冲突吗?不太可能
    • 蟒蛇3。6搞乱环境变量?不太可能
    • 蟒蛇3。6搞乱DLL,造成依赖冲突?不大可能发生的

    据我所知,这些问题是无关的,因为函数返回类型是bool,并且与源代码精确一致。和py3。8个工程。

    Python变更日志 3.6 3.7 3.8

    更新2021-11-04 1

    我曾经 catch load my_lib catch load libstdc++

    当使用Py3时。8 AcANDA环境,我的C++ DLL被加载(第一个catch),然后它加载LIbSTDc++ + 6。动态链接库 它就存储在它旁边

    使用pip venv Py3时。6,加载我的C++ DLL(第一个catch), 然后加载libstdc++-6。dll来自我的GNAT安装(第二个捕获) .

    到目前为止,这可能是我能发现的主要区别。 我非常确定2 libstdc++有不同的版本。

    python的内容 os.environ 两个环境之间的输出略有不同,主要是由于环境变量 LIBRARY_ROOTS 指向相应的python安装库文件夹(在这两种情况下 PATH

    尝试不同的 libstdc++-6。动态链接库 libstdc++-6。动态链接库 版本对观察到的行为没有影响。 看起来Python版本更改了DLL的执行。

    0 回复  |  直到 4 年前
    推荐文章