最近工作上发现一个比较复杂的代码出现随机报错问题,话不多说,直接debug模式开启ASAN机制构建程序,
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g -fstack-protector -fsanitize=address -fno-omit-frame-pointer")
很快能定位到报错的行,调用某个对象的成员函数的内部报错,说某个成员锁对象有问题,非法读取内存之类的。然后围绕这个锁,看了相关代码,没发现问题。干脆屏蔽这个锁的访问,发现访问某些成员变量也开始报错了,很奇怪,第一感觉是如果对象本身为空,外部调用的时候就应该报错了阿。
实在是想不通,看了一圈代码,也没发现明显问题,难道是ASAN此时报错较晚?干脆做个实验吧。代码如下:
#include <memory>class Person {
public:Person(const std::string& name) : name(name) {std::cout << "Construct Person: " << name << std::endl; }~Person() {std::cout << "Destroy Person: " << name << std::endl;}void print() {printf("xx\n");std::cout << "Name: " << name << std::endl; }
private:std::string name;
};int ptrTest() {// 使用make_shared创建shared_ptr实例auto p1 = std::make_shared<Person>("John");// 直接创建shared_ptrstd::shared_ptr<Person> p2 = std::make_shared<Person>("Mary");// 使用get()获取原始指针Person* rawPtr = p1.get();// 使用重载的->调用成员函数p1->print();// shared_ptr支持 copystd::shared_ptr<Person> p3;// = p1;if(p3) {p3->print();}// 当所有shared_ptr都离开作用域或被重置时,对象才会被销毁return 0;
}int main() {ptrTest();
return 0;
}
果不其然,p3不赋值的情况下,debug模式下也能进入print内部进行调用,并不报错,如果print内部访问成员变量,那么此时报错,说读取非法内存,asan此时才报错,如果print内部完全不访问任何成员变量,那么整个过程可以顺利进行!即使是Debug模式。
那么最简单的解决方案就是调用智能指针的成员之前,就先检查指针本身是否合法了。直接if判断就行。最根本的解决方法是找到为什么没被赋值,这是必须要解决的问题了。