在不同的编译单元中,控制条件编译的共享(可能是模板化的头)预处理器指令中的编译器参数拼写错误导致的二进制不兼容性保护?
实施例。
g++ ... -DYOUR_NORMAl_FLAG ... -o libA.so
/**Another compilation unit, or even project. **/
g++ ... -DYOUR_NORMA1_FLAG ... -o libB.so
/**Another compilation unit, or even project. **/
g++ ... -DYOUR_NORMAI_FLAG ... main.cpp libA.so //The possibilities!
最近,我遇到了一个奇怪的错误:症状是单个SIGSEGV,在重新编译后似乎总是出现在同一个位置。这让我相信存在某种内存损坏,实际的底层指针根本不是指针,而是一些数据部分。
我将你从漫长而艰苦的旅程中拯救出来,几乎完成了两个非常好的工作日来追踪问题。足以说,Valgrind,GDB,nm,readelf,电围栏,GCC的堆栈粉碎保护,以及一些更多的措施/方法/方法都失败了。
在彻底的破坏中,我的注意力转向了构建过程中最精细的细节,类似于:
仅当大型库被用作静态或动态库依赖项时(即动态链接器自动加载它,没有dlopen) 有问题吗?测试案例中,库的所有代码都包含在测试中,一切正常:这是最重要的线索。
最后,事实证明这是最简单的事情:单个(!)拼写错误。
事实证明,编译标志与测试套件中的单个字符不同,而大型库:一个控制小型库行为的定义拼写错误。 关键信息morsel:小型库有一些模板。这些在每种情况下都直接使用,没有事先进行明确的实例化。当标志被切换时,其中一个模板化类的内容发生了变化:如果定义了标志,则某些数据字段根本不存在! 链接器没有注意到这一点。 (由于该类是模板化的,因此结果符号很弱。) 代码使用动态强制转换,受此问题影响的类继承自受损的类 - >事情向南发展。
我的问题如下:您如何防范此类问题?是否有解决此特定问题的工具或解决方案?
我已经想到了两件事,并且相信不能在目标文件级别上构建保护:
我想继续前进并熄灭一些可能在某些读者中引起煽动的火焰余烬:“不要使用预处理器符号”这里不是一个选项。
我知道:
答案 0 :(得分:0)
如果重要,请没有默认情况。
#ifdef YOUR_NORMAL_FLAG
// some code
#elsif YOUR_SPECIAL_FLAG
// some other code
#else
// in case of a typo, this is a compilation error
# error "No flag specified"
#endif
如果过度使用条件编译,这可能会导致大量的编译器选项,但是有很多方法可以解决这个问题,比如定义配置文件
flag=normal
flag2=special
由构建脚本解析并生成选项,可以检查拼写错误或者可以直接从Makefile中解析。