如何在 C++ 中捕获内存损坏?

How can you catch memory corruption in C++?

我有一个 std::string 似乎以某种方式损坏了。有时字符串析构函数会触发访问冲突,有时通过 std::cout 打印它会产生崩溃。

如果我按如下方式在结构中填充字符串,back_padding 在我的代码中的一个相对一致的点上会稍微损坏:

struct Test {
    int front_padding[128] = {0};
    std::string my_string;
    int back_padding[128] = {0};
};

有没有办法保护前后padding数组,这样写入就会出现异常什么的?或者也许可以使用一些工具来捕捉写入此内存的罪魁祸首?

平台:Windows 使用 MSVC 构建的 x64。

总的来说,你必须解决代码卫生问题,这是一个相当广泛的话题。听起来您可能有越界写入,或者使用悬空指针,甚至在使用指针时出现竞争条件,但在后一种情况下,bug 的可见性会受到观察的影响,就像众所周知的量子叠加态中的猫一样。

调试此类恶意写入源的一种肮脏方法是创建数据断点。如果 bug 看起来是确定性的并且不是“heisenbug”,它会特别有效。在调试会话期间在 MSVS 中是可能的。在 gdb 中,可以使用观察断点。

您可以指向 std::string 存储,或者在您的实验案例中指向前填充数组,以尝试触发发生写操作的断点。

How can you catch memory corruption in C++?

使用现代编译器的最佳方式是使用 address sanitizer 进行编译。这会准确地插入您在自动(堆栈)和动态(堆)分配周围描述的那种保护区,并检测它们何时被践踏。它内置于 Clang、GCC 和 MSVC 中。

如果您没有编译器支持,或者需要在不重新编译的情况下诊断现有二进制文件中的问题,您可以使用 Valgrind.

经过清理的可执行文件以全速运行,尽管它正在做更多的工作并且故意采用不太适合缓存的内存布局;预计它比等效的未检测构建慢 2 倍。

运行 在 valgrind 下要慢得多(memcheck 预计 10x-30x),但会捕获更多类型的错误,如果你不能重新编译,这是你唯一的选择。