首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用不同的C++标准编译的链接库是否存在隐患?

使用不同的C++标准编译的链接库是否存在隐患?
EN

Stack Overflow用户
提问于 2021-05-12 17:03:22
回答 2查看 74关注 0票数 3

让我们假设我们已经准备了一个共享库,它是用gcc9在std-c++=14中编译的,名为A.so。我们希望将这个共享库链接到一个新项目,该项目的源文件将在std-c++=17中使用clang++13进行编译。让我们将新项目的目标命名为B.out

我想知道这计划会否有潜在的危险?如果我们在A和B中定义了具有相同名称的函数,它们是否会相互冲突或产生意外的输出?

EN

回答 2

Stack Overflow用户

发布于 2021-05-13 22:33:01

有几个危险需要注意。

C++名称损坏是有意为非标准的。不同的编译器可能会为相同的代码产生不同的符号。因此,从一个编译器编译的代码调用另一个编译器编译的代码可能会导致链接器错误。

拥有一个所有编译器都使用的标准损坏方案最初看起来可能很有用,但在许多其他方面,编译器无法进行互操作(例如异常、虚函数),因此,由于链接器错误而导致的早期破坏可以防止更微妙的问题。

GCC和朗是非常亲密的wrt破坏,请看这里:https://jplehr.de/2019/10/25/name-mangling-in-c-with-clang-and-gcc/

然而,另一个危险是标准库的互操作性。如果将libstdc++ (来自GCC)与libc++ (来自LLVM)混合使用,则会出现更多问题。例如,如果您在两个代码体之间传递来自标准库的对象(例如std::string,std::map),则它们很可能不能互操作。每个库中的对象可能具有不同的内存布局,从而导致损坏和(理想情况下,因为明显的bug比细微的bug更好)崩溃。

最好将这两部分C++代码完全分开,只让它们通过APIs相遇。

票数 1
EN

Stack Overflow用户

发布于 2021-05-14 00:21:29

我能想到两种问题类型:

A.so

  • (Accidentally)接口中使用标准库类型的
  1. A.so.

中导出具有标准库类型的符号

让我们把重点放在一个平台上,比如说Linux。在Linux上,共享库遵循ELF规范。它们导出其符号的子集("ELF-visible“符号)。只有那些导出的符号才能通过动态加载器在运行时由像B.out这样的使用者链接或找到。

libstdc++应该是向后兼容的。也就是说,如果您动态链接libstdc++,您的程序通常只会加载一个libstd++.so库。可以有多个模块(可执行的动态库)使用此libstdc++中的符号。由于向后兼容,它们都应该可以工作。这种向后兼容性是通过ELF符号版本控制实现的。然而,符号版本控制只针对libstdc++中的符号,而不是仅存在于标题中的标准库类型(例如模板)。

关于第一个问题类型:标准库类型在libstdc++中的布局不稳定。如果您在A.so中构造一个std::vector<int>类型的对象并将其传递给B.out,它们可能会为该类型采用不同的二进制布局,并且它将以奇妙的方式中断。如果类对象的空间由B.out分配/释放,这甚至会影响A.so中的类成员。Here's one example.

关于第二个问题类型:默认情况下,所有具有外部链接的符号也是从共享对象导出的。因此,标准库模板实例化也可以导出,这通常是偶然的。如果你意外地创建了一个像std::vector<Foo>::push_back(..)这样的ELF可见符号,那么A.soB.out都有可能提供这个符号。但由于我们是动态链接的,所以A.so会优先使用B.out中的链接。当然这是不好的,因为Foostd::vectorA.soB.out中可能有不同的布局。这也可能发生在全局/静态变量中,比如CoW-std::string的空字符串,或者locale facet。这主要可以通过禁用默认ELF可见性(-fvisibility=hidden),然后显式导出单个符号来解决。但即便如此,这仍然很棘手,您应该检查最终导出了哪些元件。也许一个链接器版本的脚本在这里会有所帮助。

关于clang vs gcc:如果你同时使用libstdc++和libc++,你很可能会遇到libstdc++和libc++之间的符号冲突。例如,两者都可能提供类似operator new(size_t)的函数。也许你很幸运,所有的符号都有正确的版本化,并且版本包含库名称。

在简单的共享对象方案中,您只需指定所需的库。您可以单独指定所需的符号。这两者之间通常没有关联。对于加载的每个库,动态加载器都会维护一个库列表以搜索符号。可以从“错误的库”(不是你打算使用的库)解析符号,但是我认为如果A.solibc++.so是兄弟依赖关系(即B.out同时加载libc++.soA.so,而A.so需要libstdc++.so),则不会发生这种情况。

应该可以使用链接器命名空间来完全隔离依赖项。

最后,我认为让它工作是可能的。问题是,你愿意解决因意外的符号冲突而产生的奇怪而奇妙的问题吗?值得吗?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67500470

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档