检测无意的弱链接符号
Detecting unintended weak link symbols
在我们公司,直到最近,我们还没有使用名称空间,因为一些编译器不能很好地支持它们。
这会导致以下错误的大量出现:
file_A.cpp
class Node {
Data *ptr;
Node() { ptr = new Data; }
~Node() { delete ptr; }
};
file_B.cpp
class Node {
vector<int> v;
Point *pt;
Node(int x,int y) { pt = new Point(x,y); v.push_back(0); }
~Node() { delete pt; }
};
void foo() {
Node n(10,10);
...
} // calls file_B::~Node() !!!
每个作者Node
都不知道其他Node
的存在,但是因为他期望这个类名可能被重用,所以他没有使用它创建一个.hpp文件。
编译器静默地删除其中一个析构函数,因为它们的签名匹配,并且该错误很难发现,因为它可能不会在不同的计算机上复制。
一旦错误被识别出来,人们就会逐渐意识到它,并试图将定义密封在未命名的名称空间中,或者避免在类体中取消对成员函数的删除。
问题1:既然你不能相信程序员总是记得防御性地编程,那么是否有一种工具可以检测这些"无意的弱链接符号"?
我所说的意外是指
Node
类在.hpp文件中没有定义,并且至少有一个类成员在类定义之间不匹配…问题2:如果我们不使用名称空间,但是我们做内联每个函数,是否有可能自动生成的函数(复制-ctor,复制-赋值,析构函数)会产生前面提到的"弱链接错误"?
方法一:将未命名的命名空间
namespace {
class Node {
Data *ptr;
Node() { ptr = new Data; }
~Node() { delete ptr; }
};
}
方法二:避免内联
class Node {
Data *ptr;
Node();
~Node();
};
Node::Node() { ptr = new Data; }
Node::~Node() { delete ptr; }
如果您的代码库足够大,可以定制一个现有的编译器来处理您的问题:
- LLVM/Clang编译器是可定制的(它是c++的,我不太了解它)。
- GCC编译器(最近的版本如4.6)是可扩展的,要么通过用C编码的插件,要么通过用MELT编码的扩展。MELT是一种(免费的,GPLv3许可的)高级领域特定语言,用于扩展GCC。
在这两种情况下,它都是几天或几周的努力,最困难的是部分理解编译器的内部表示(Gimple &
我是MELT的主要作者,我很乐意帮助你使用MELT,所以请随时与我联系。
《c++和链接器》是一本关于这个问题的非常有趣的读物。具体参见"没有强制执行的规则毫无意义"一节。
一种见解是,您可以通过解析目标文件来检测"弱"符号,并查找"W":
$ nm -C foo.o | grep doSomething
00000000 W doSomething()
因此,您可以添加一个后处理步骤,自动收集这些并列出重复的内容。您可以将它们与预期重复项的主列表进行比较,如果有任何新的重复项,则发出标记。
另一个选项可能是gcc的-Fno-weak
选项。从文档中还不清楚副本会发生什么,但找出答案可能会很有趣。
链接的文章也回答了你的第二个问题("上述现象"指的是删除重复弱符号的所有实例,只保留一个实例):
在某些情况下编译器必须创建一个符号尽管它内联了函数。例如,当函数指针引用函数。所以,上述现象当启用优化时,它并不总是消失。
- 使用gcc从静态链接的文件中查找可选符号
- 链接器找不到在虚拟类 c++ 中访问的静态字段的符号
- Windows 链接器是否使用 LoadLibrary 解析 DLL 中未定义的符号?
- 如果我想链接静态库并删除未使用的符号.txt我应该如何处理 Cmakelist
- clang:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用) - 体系结构的未定义符号 x86_64:
- emscripten 链接全局命名符号乘法定义
- 体系结构x86_64的未定义符号:链接器错误
- 共享对象、符号、C/C++ 库链接和加载
- 如何防止 CMake 在构建时(而不是在安装时)为共享库创建符号链接?
- 如何将空文件夹和符号链接添加到存档 - libarchive
- 协议缓冲区的静态链接会导致与现有符号冲突
- 链接器错误:切换到unicode生成给出:未解析的外部符号WinMain
- SWIG链接器:未定义符号:_ZN2cv8fastFreeEPv(cv::fastFree(void*))
- 使用共享库编译可执行文件时仅链接所需的符号
- 为什么链接器报告全局函数的乘法定义符号,而不是类静态方法
- 未定义的引用,即使库正在链接并且它包含正确的符号
- C++ 链接器错误 LNK 2019 函数中引用的未解析的外部符号
- boost::存在符号链接不取消引用
- 检测无意的弱链接符号
- c++ Linux静态变量的双重析构.链接符号重叠