c++ - 防止或检测“this”在使用过程中被删除
问题描述
我经常看到的一个错误是容器在迭代时被清除。我试图整理一个小示例程序来演示这种情况。需要注意的一件事是,这通常会发生在许多函数调用深处,因此很难检测到。
注意:这个例子故意展示了一些设计不佳的代码。我正在尝试找到一种解决方案来检测由编写此类代码引起的错误,而无需仔细检查整个代码库(约 500 个 C++ 单元)
#include <iostream>
#include <string>
#include <vector>
class Bomb;
std::vector<Bomb> bombs;
class Bomb
{
std::string name;
public:
Bomb(std::string name)
{
this->name = name;
}
void touch()
{
if(rand() % 100 > 30)
{
/* Simulate everything being exploded! */
bombs.clear();
/* An error: "this" is no longer valid */
std::cout << "Crickey! The bomb was set off by " << name << std::endl;
}
}
};
int main()
{
bombs.push_back(Bomb("Freddy"));
bombs.push_back(Bomb("Charlie"));
bombs.push_back(Bomb("Teddy"));
bombs.push_back(Bomb("Trudy"));
for(size_t i = 0; i < bombs.size(); i++)
{
bombs.at(i).touch();
}
return 0;
}
任何人都可以提出一种保证这种情况不会发生的方法吗?我目前可以检测到这种事情的唯一方法是用 mmap / mprotect 替换全局new和delete并在空闲内存访问后检测使用。但是,如果向量不需要重新分配(即仅删除了一些元素或新大小还不是保留大小),这和 Valgrind 有时无法拾取它。理想情况下,我不想克隆大部分 STL 来制作一个 std::vector 版本,该版本总是在调试/测试期间重新分配每个插入/删除。
一种几乎可行的方法是,如果std::vector改为包含std::weak_ptr,则使用.lock()创建临时引用可防止在 classes 方法内执行时将其删除。但是,这不能与std::shared_ptr一起使用,因为您不需要lock()并且与普通对象相同。仅仅为此创建一个弱指针容器是很浪费的。
任何人都可以想出一种方法来保护自己免受这种伤害。
解决方案
最简单的方法是使用链接的Clang MemorySanitizer运行单元测试。让一些持续集成的 Linux 机器在每次推送到 repo 时自动执行它。
MemorySanitizer 具有“破坏后使用检测”(标志-fsanitize-memory-use-after-dtor
+ 环境变量MSAN_OPTIONS=poison_in_dtor=1
),因此它会炸毁执行代码的测试,并使您的连续集成变为红色。
如果您既没有单元测试也没有持续集成,那么您也可以使用 MemorySanitizer 手动调试代码,但与最简单的方法相比,这很难。所以最好开始使用持续集成和编写单元测试。
请注意,在运行析构函数但内存尚未释放后,可能存在内存读取和写入的正当原因。例如 std::variant<std::string,double>
. 它让我们可以分配它,std::string
因此double
它的实现可能会破坏string
并重用相同的存储空间double
。不幸的是,目前过滤此类情况是手动工作,但工具会不断发展。
推荐阅读
- arrays - Excel VBA 使用数组加速代码
- matlab - 评估符号 matlab 函数
- java - 在 MongoDB 的嵌入式文档中将元素插入到数组中
- python - 带有字符串列表的 Python DataFrame 列不会展平
- sql - 从乘法建立一个总和
- ios - 如何正确地使 UICollectionView 中补充视图的布局无效
- docker - 在 Vagrant 中的 docker-compose 中设置卷
- nixos - 是否可以(或建议)使用 NixOps 将 NixOS 安装到 USB 闪存驱动器?
- xml - 将 importXML 与 php 填充的网站一起使用并抓取到 googlesheets
- visual-studio - 如何在不打开外部浏览器实例的情况下在 Visual Studio 中查看代码文档?