【问题标题】:Understanding GCC 5's _GLIBCXX_USE_CXX11_ABI or the new ABI了解 GCC 5 的 _GLIBCXX_USE_CXX11_ABI 或新的 ABI
【发布时间】:2016-01-02 22:56:23
【问题描述】:

https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html

我在 GCC 5 上使用 std::string 时遇到了崩溃/valgrind 问题。上面的链接暗示从 GCC 5.x 开始的 ABI 发生了变化。 libstd++ 的新默认 ABI 是 C++11/14...,它与旧 ABI 不兼容。有一种方法可以使用定义来选择较旧的 ABI。

我正在尝试了解 ABI 之间的区别,但尚未找到详细信息。我想帮助理解:

  1. 需要修复 std::string 的哪些问题才能与新的 ABI 兼容?它们是否与写时复制相关?
  2. 这些更改会破坏旧 ABI 的功能吗?
  3. 关于让 _GLIBCXX_USE_CXX11_ABI 工作的任何提示?

关于我遇到的问题的更多详细信息 (https://github.com/YasserAsmi/jvar/issues/21) 该项目在 GCC 4.8 和 Clang 中运行良好。使用 GCC,相同的代码拒绝运行:

x_misc(33112,0x7fff728c2000) malloc: *** error for object 0x7fd639c034cc:    pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

这是部分 Valgrind 输出:

==33027== Invalid read of size 1
==33027==    at 0x1006F78BA: _platform_memmove$VARIANT$Nehalem (in /usr/lib/system/libsystem_platform.dylib)
==33027==    by 0x100009388: jvar::Variant::toString[abi:cxx11]() const (in bin/ex_misc)
==33027==    by 0x1000023A7: bugreport() (in bin/ex_misc)
==33027==    by 0x1000133B8: main (in bin/ex_misc)

该项目使用 std::string 并具有一些自定义内存管理。它正在使用放置新构造函数等执行一些非典型但有效的操作。我试图更好地了解 API 影响了哪种代码以及如何修复它——一个开始的地方。

【问题讨论】:

  • 如果您始终如一地编译所有对象(使用相同的 ABI),那么您得到的错误是由于您的程序中的错误或(不太可能)新 ABI 实现中的实际错误.在任何一种情况下,将其分解为一个小测试用例并在此处发布(minimal reproducible example)。

标签: c++ c++11 gcc


【解决方案1】:
  1. 旧的 std::string 不符合 C++11,因为该标准禁止写时复制实现。没有办法在不破坏 ABI 的情况下创建合规的std::string,因此他们这样做是为了返回到不合规的版本以实现 ABI 兼容性。

  2. 是的。

  3. 确保程序中的所有翻译单元都使用相同的_GLIBCXX_USE_CXX11_ABI 值,这样就可以了。如果您将它们在翻译单元中混合使用,您肯定会遇到问题。如果您在不同的翻译单元中具有不同的定义值,并且彼此之间不交流strings,那么您可能没问题。

【讨论】:

  • 在 #1 上,新 ABI 会破坏什么类型的旧代码。我可以使用 std::strings 在旧代码中查找什么并修复它?谢谢
  • 好答案。值得一提的是,在 Debian 中,我们根据第 3 点采用了重新编译所有内容。参见例如this wiki entry for more
  • @YasserAsmi 没有什么可修复的,新的 ABI 只需要您链接在一起的所有内容以使用相同的 ABI。
  • @nos,我更新了原始帖子...我的项目在 GCC 4.8 中运行良好,而 CLANG 在 GCC 5 中无法运行。其他项目报告了类似的问题:例如:github.com/facebook/folly/issues/316跨度>
  • 您可能需要重新编译。一切。这就是我在工作中使用各种基于 C++ 的打包的 R 堆栈所做的。
【解决方案2】:

COW 和非 COW 字符串之间有一个有趣的区别,例如:

std::string some_string;
std::string foo()
{
   return some_string;
}

char const *s = foo().c_str();
printf("%s\n",s);

这将与 COW 字符串一起使用,因为由 some_string 返回的 c_str() 和 foo 指向相同的内存,但是当它不是 COW 时,一旦 foo 返回的 std::string 被破坏,s 就会失效。

从那里的示例中,您应该朝这个方向看。

【讨论】:

  • K... 但通过尝试使用从创建的临时 std::string 中提取的指针作为来自foo() 的返回值,这不仍然是未定义的行为吗?由于允许使用 COW,但不是必需的,因此您不能假设它正在发挥作用。
  • 这是未定义的行为,但是当字符串为 COW 时会导致隐藏的错误,而不是使用非 COW 字符串。
  • 那你怪错了。隐藏的bug是因为Undefined Behaviour,而不是COW的存在。与取消引用 nullptr 导致(或不导致)一个程序崩溃没有什么不同。
  • 我不是在责怪我是在解释如何使用旧的 ABI,而使用新的不是 - 并且代码似乎具有类似的功能
猜你喜欢
  • 2018-01-07
  • 1970-01-01
  • 2016-07-18
  • 1970-01-01
  • 2021-11-26
  • 1970-01-01
相关资源
最近更新 更多