首页 > 解决方案 > 通过简单的动态链接来违反一个定义规则

问题描述

问题: ELF 平台上的动态链接 C++ 程序是否总是因违反单一定义规则而处于产生未定义行为的边缘?

更具体:通过简单地编写一个共享库来公开一个函数

#include <string>
int __attribute__((visibility("default"))) combined_length(const char *s,
                                                           const char *t)
{
    const std::string t1(t);
    const std::string u(s + t1);
    return u.length();
}

并通过 GCC 7.3.0 编译它

$ g++ -Wall -g -fPIC -shared \
      -fvisibility=hidden -fvisibility-inlines-hidden \
      -o liblibrary.so library.cpp

operator+()我创建了一个二进制文件,它为指向字符数组和字符串的指针定义了一个弱符号:

$ readelf -sW liblibrary.so | grep "_ZStpl"
    24: 0000000000000ee2   202 FUNC    WEAK   DEFAULT   12 _ZStplIcSt11char_traitsIcESaIcEENSt7__cxx1112basic_stringIT_T0_T1_EEPKS5_RKS8_
    ...

但是看看我得到的标准库二进制文件

$ readelf -sW /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep "_ZStplIcSt11char_traitsIcESaIcEENSt7__cxx1112basic_stringIT_T0_T1_EEPKS5_RKS8_"
  2829: 000000000012b1c0   169 FUNC    WEAK   DEFAULT   13 _ZStplIcSt11char_traitsIcESaIcEENSt7__cxx1112basic_stringIT_T0_T1_EEPKS5_RKS8_@@GLIBCXX_3.4.21

这就是我要说的重点:哦,天哪,我库中的符号也应该附有一个版本!

在当前状态下我很好,因为我可以假设标准库二进制文件是使用与我的库相同的头文件构建的。但是如果 libstdc++-v3 的实现者决定定义这个函数的新版本并用 标记它会发生GLIBCXX_3.4.22什么?由于符号很弱,运行时链接器可以自由决定是采用我的库的未版本化符号还是 libstdc++-v3 的版本化符号。如果我将我的库发送到这样的系统,我会在那里引发未定义的行为。一些符号版本应该为我解决了。

标签: c++linuxelfc++-standard-libraryone-definition-rule

解决方案


推荐阅读