代码之家  ›  专栏  ›  技术社区  ›  n. m. could be an AI

STD:ReGEX和双ABI

  •  6
  • n. m. could be an AI  · 技术社区  · 6 年前

    今天我发现了一个有趣的例子,双libstdc++abi影响了库的兼容性。

    长话短说,我有两个库,它们都使用STD::一个是用CXx11 ABI构建的,另一个不是。当这两个库在一个可执行文件中链接在一起时,它在启动时崩溃(之前 main 输入)。

    这些库是不相关的,并且不公开任何提到 std:: 类型。我认为这样的图书馆应该对双重ABI问题免疫。显然不是!

    可以通过以下方式轻松复制问题:

    // file.cc
    #include <regex>
    static std::regex foo("(a|b)");
    
    // main.cc
    int main() {}
    
    // build.sh
    g++ -o new.o file.cc
    g++ -o old.o file.cc -D_GLIBCXX_USE_CXX11_ABI=0 
    g++ -o main main.cc new.o old.o
    ./main
    

    输出为:

    terminate called after throwing an instance of 'std::bad_alloc'
      what():  std::bad_alloc
    Aborted (core dumped)
    

    不管我做什么,这个问题一直存在。 file.cc 可以生成两个单独的源文件,编译成单独的共享库,这两个 std::regex 对象可能有不同的名称,它们可以是全局的、静态的或自动的(需要从调用相应的函数 主要的 然后)。这些都没用。

    显然(这是我简短调查的结果),libstdc++regex编译器有一些内部静态数据存储 std::string 当两个ABI不兼容的代码试图使用该数据时,它会对 STD::字符串 物体。

    所以我的问题是:

    • 有解决这个问题的方法吗?
    • 这是否应被视为libstdc++中的错误?

    这个问题在几个版本的g++/libstdc++(我尝试了一些5.4到7.1的版本)。libc++不会发生这种情况。

    1 回复  |  直到 6 年前
        1
  •  4
  •   Yuki    6 年前

    这个问题源于libstdc++为什么 dual ABI . 从这两个重要的陈述中:(1)它被专门介绍为在如何 string (以及与本讨论无关的其他内容)作品;(2) _GLIBCXX_USE_CXX11_ABI 独立于一个方言,用于编译C++ 03和C++ 11。

    regex 模块在第11个标准中引入,并在内部使用字符串。因此,您构建了C++- 11(或更高)模板 basic_regex 代码 _GLIBCXX_USE_CXX11_ABI=0 . 这意味着你正在使用C++ 11。 正则表达式 对象,使用字符串的pre-c++-11实现。

    这样行吗?取决于如何 正则表达式 使用字符串,如果它确实依赖于新的实现(例如,写时禁止复制),则为“否”,否则为“是”。会发生什么?什么都可以。

    从根本上说,你不应该使用 _ glibcxx_使用_cx11_abi=0 对于任何使用后C++ 03方言的新代码(即C++-11,14,17,…),因为它引入了与标准对象的新保证不兼容的实现,尤其是 std::string .

    我能用吗 _ glibcxx_使用_cx11_abi=0 用STD & Gt=C++- 11?GCC开发人员注意到,您可以使用旧的ABI运行新的东西,这有利于使用旧的共享库运行新的功能。然而,这可能不是一个好主意,也因为代码在一个新的标准中,但是标准库不符合这个标准,以后可能会很糟糕。你的问题就是一个例子。你可以把两个ABI混合在一起,我们就在这里,它不起作用。

    _ glibcxx_使用_cx11_abi=0 例如,如果你打电话, foo(std::string const&) 在一些库中定义,用一个旧的abi编译。然后,在新的源文件中,您希望使用旧的ABI编译这个源文件。但所有其他的来源,你会保持一个新的ABI。

    这个问题在几个版本的g++/libstdc++(我尝试了一些5.4到7.1的版本)。libc++不会发生这种情况。

    libc++ 没有这种二元性,即单一性 一串 实施。

    我没有给出一个明确的答案,这个例外是从哪里来的,或者为什么。我只能猜测有一些共享的全球资源与 正则表达式 , 一串 locale ABIS之间的区别不明显。不同的ABI使用它的方式也不同,它们可以导致任何事情,例如异常、段错误、任何意外行为。imho,我更喜欢遵守我上面提到的规则,这些规则最能反映 _ glibcxx_使用_cx11_abi 双ABI。