C++ 捕捉悬空参考
假设有以下一段代码
struct S {
S(int & value): value_(value) {}
int & value_;
};
S function() {
int value = 0;
return S(value); // implicitly returning reference to local value
}
编译器不产生警告(-Wall),这个错误很难捕捉.
compiler does not produce warning (-Wall), this error can be hard to catch.
有哪些工具可以帮助解决此类问题
What tools are out there to help catch such problems
推荐答案
有一些基于运行时的解决方案,可以检测无效指针访问的代码.到目前为止,我只使用过 mudflap(自 4.0 版以来已集成在 GCC 中).mudflap 尝试跟踪代码中的每个指针(和引用),并检查每个访问是否指针/引用实际上指向其基类型的活动对象.下面是一个例子:
There are runtime based solutions which instrument the code to check invalid pointer accesses. I've only used mudflap so far (which is integrated in GCC since version 4.0). mudflap tries to track each pointer (and reference) in the code and checks each access if the pointer/reference actually points to an alive object of its base type. Here is an example:
#include <stdio.h>
struct S {
S(int & value): value_(value) {}
int & value_;
};
S function() {
int value = 0;
return S(value); // implicitly returning reference to local value
}
int main()
{
S x=function();
printf("%s
",x.value_); //<-oh noes!
}
在启用泥板的情况下编译:
Compile this with mudflap enabled:
g++ -fmudflap s.cc -lmudflap
并运行给出:
$ ./a.out
*******
mudflap violation 1 (check/read): time=1279282951.939061 ptr=0x7fff141aeb8c size=4
pc=0x7f53f4047391 location=`s.cc:14:24 (main)'
/opt/gcc-4.5.0/lib64/libmudflap.so.0(__mf_check+0x41) [0x7f53f4047391]
./a.out(main+0x7f) [0x400c06]
/lib64/libc.so.6(__libc_start_main+0xfd) [0x7f53f358aa7d]
Nearby object 1: checked region begins 332B before and ends 329B before
mudflap object 0x703430: name=`argv[]'
bounds=[0x7fff141aecd8,0x7fff141aece7] size=16 area=static check=0r/0w liveness=0
alloc time=1279282951.939012 pc=0x7f53f4046791
Nearby object 2: checked region begins 348B before and ends 345B before
mudflap object 0x708530: name=`environ[]'
bounds=[0x7fff141aece8,0x7fff141af03f] size=856 area=static check=0r/0w liveness=0
alloc time=1279282951.939049 pc=0x7f53f4046791
Nearby object 3: checked region begins 0B into and ends 3B into
mudflap dead object 0x7089e0: name=`s.cc:8:9 (function) int value'
bounds=[0x7fff141aeb8c,0x7fff141aeb8f] size=4 area=stack check=0r/0w liveness=0
alloc time=1279282951.939053 pc=0x7f53f4046791
dealloc time=1279282951.939059 pc=0x7f53f4046346
number of nearby objects: 3
Segmentation fault
需要考虑的几点:
- mudflap 可以微调它应该检查和做什么.阅读 http://gcc.gnu.org/wiki/Mudflap_Pointer_Debugging 了解详情.
- 默认行为是在违规时引发 SIGSEGV,这意味着您可以在调试器中找到违规.
- mudflap 可能是个婊子,特别是当您与未使用 mudflap 支持编译的库进行交互时.
- 它不会在创建悬空引用的地方吠叫(返回 S(value)),只有当引用被取消引用时.如果您需要这个,那么您将需要一个静态分析工具.
附言需要考虑的一件事是,向 S() 的复制构造函数添加一个 NON-PORTABLE 检查,它断言 value_ 未绑定到寿命较短的整数(例如,如果 *这位于它所绑定的整数堆栈的旧"插槽上).这是高度特定于机器的,当然可能很难做到正确,但只要仅用于调试就可以了.
P.S. one thing to consider was, to add a NON-PORTABLE check to the copy constructor of S(), which asserts that value_ is not bound to an integer with a shorter life span (for example, if *this is located on an "older" slot of the stack that the integer it is bound to). This is higly-machine specific and possibly tricky to get right of course, but should be OK as long it's only for debugging.
相关文章