调试对父函数"belonging"内存的意外使用

Debug unintended use of memory "belonging" to parent function

本文关键字:意外 内存 belonging 函数 调试      更新时间:2023-10-16

假设我有一个从给定软件工具调用的函数foo(在 C/C++ 中)。

函数foo只允许写入foo分配的内存或foo调用的函数之一,但不允许写入在调用foo之前已执行的函数分配的内存。

我强烈怀疑,在某些地方foo写入内存是不允许的。

有没有办法系统地调试此行为?也许是瓦尔格林德的一些花哨的旗帜?

Valgrind 手册有一些 Valgrind 函数,您的程序可以调用这些函数。

看起来VALGRIND_MAKE_MEM_NOACCESS可能是你想要的。

您可以使用自定义分配器(想到加速池)来确保连续分配要"保护"的所有内存。

接下来,在该内存区域中的任何数据发生更改时设置硬件断点。

我会编写一个 GDB 脚本,在您的函数上设置断点,然后在您怀疑正在更改的内存上设置硬件监视,然后继续。

如果函数 foo 正在修改该内存,则硬件手表将在执行该指令时触发该内存。

GDB 脚本可能如下所示:

break foo
commands
up
watch array
down
continue
end

我没有测试,它可能需要调整,尤其是手表表达式。您可能只能监视一个数组元素。我相信硬件观察点实际上只能监视一个整数大小块:32 位上的 4 个字节或 64 位上的 8 个字节。

foo() 可以写入其范围之外的内存的唯一方法是,如果该内存是全局的,即 extern 变量,或者如果 foo() 有一个或多个参数,这些参数本来是只读的,但不知何故它们被修改了。

要验证调用参数是否被修改,您可以创建一个结构来保存参数,并在返回之前将原始参数与保存的参数进行比较。

struct foo_args {
    int a;
    char *b;
};         
void
foo(int a, char *b) 
{                 
    struct foo_args args;
    args.a = a
    args.b = strdup(b);
    /* The rest of the foo() code. */
    if (args.a != a || strcmp(args.b, b) != 0) {
        printf("error - args got modifiedn");
    }    
    free(args.b);
}               

如果上述内容没有捕获它,那么可能的情况是全局、堆栈或堆内存已损坏。

要让 valgrind 运行该工具可能不切实际,在这种情况下,您需要为 foo() 创建一个"包装器",并确保使用 valgrind 或类似的东西,它不会做它不应该做的事情。 另一种选择是使用调试库来跟踪/监视内存使用情况,并在发生内存错误时标记它们。