如何检测或防止野指针

How to detect or prevent wild pointer

本文关键字:指针 何检测 检测      更新时间:2023-10-16

这段非常简单的代码演示了在复杂的环境中使用野指针会导致什么样的问题。

int main()
{
    int *a1 = new int;
    int *tmp = a1;
    delete a1;
    // Now, the tmp pointer is a wild pointer, it's dangerous.
    int *a2 = new int;
    delete tmp;
    // Now, the a2 pointer may be a wild pointer.
}

有什么方法可以发现或防止这个问题吗?智能指针在这里有帮助吗?

使用智能指针。为什么不呢?

你的代码是无效的,会导致未定义的行为,但不管怎样- c++在内存使用方面不是很严格,这就是它的美丽(和诅咒…)。有一些外部工具可以帮助检测泄漏(尽管不是您所展示的那种情况),但归根结底还是要使用正确的结构和正确的编程。c++有很大的灵活性,但如果使用不当,就会出现严重的bug。

这个问题的解决方法很简单:

始终清楚代码中资源的所有权,并通过使用管理资源生命周期的类来强制这种所有权。

在这种情况下(假设您需要使用指针),我建议的生命周期如下:

//Limit the scope of the variables to the minimum required:
{
    //a1 owns the pointer, so make it a `unique_ptr`
    std::unique_ptr<int> a1(new int);
    //tmp does not own the pointer, so make it a raw pointer
    //limit its scope to a shorter scope than a1
    int *tmp = a1.get();
}
//now the tmp pointer does not exist. It cannot be dangerous
//A similar strategy applies here
{
    //a2 owns the pointer
    std::unique_ptr<int> a2(new int);
}
//Again, a2 goes out of scope before any damage can occur.

您可以使用(至少在Linux上)像valgrind这样的工具来追踪这些bug。

你也可以使用Boehm的垃圾收集器(而不用担心释放内存)。

有些类(我认为设计得很糟糕)需要删除(即因为它们在析构函数中做重要的事情,除了释放内存)或者不应该有指向实例的手动指针。

阅读更多关于RAII的信息(RAII在c++中很常见,但不是通用的咒语:例如,好的Ocaml代码不遵循RAII)。

你可以使用智能指针

唯一的方法是尽可能多地对代码进行单元测试,使用valgrind等工具运行程序和单元测试,并希望捕获所有内存访问问题。

int *a2 = new int;
delete tmp;
//now, the a2 pointer may be a wild pointer

不,指针a2指向一个有效的(非空闲的)位置。

据我所知,没有这样的方法来确定指针是否指向内存中的有效(非释放)位置。

对于您的第一个示例,您可以使用std::shared_ptr对分配的内存位置的共享所有权进行建模。

有了C,没人能阻止你搬起石头砸自己的脚。

有很多方法可以让你的生活更轻松,比如c++智能指针:http://en.wikipedia.org/wiki/Smart_pointer#C.2B.2B_Smart_Pointers

诸如valgrind之类的工具将覆盖delete语句,并将内存标记为无效,以便可以检测和报告后续访问。例如,常用的做法是在调试时用0xDEADBEEF这样的值覆盖应该被删除的内存,这样您很快就知道正在访问已删除的内存区域。

对于生产,您通常希望跳过写入不再需要的内存,所以这些东西应该只在调试模式下启用。