gpt4 book ai didi

c++ - Valgrind 报告标准库中未初始化的值 (vfprintf.c)

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:53:09 26 4
gpt4 key购买 nike

我有一个函数可以将 vsnsprintf 放入在堆栈上创建的对象的临时缓冲区中。

在对象的构造函数中,我将缓冲区的第一个字符初始化为空。

Valgrind 提示在 vfprintf.c 的堆栈上创建了一个未初始化的值

下面是完整的工作示例,后面是 valgrind 输出

#include <stdio.h>
#include <stdarg.h>
#include <string.h>

struct tmp_buf
{
tmp_buf() { *b = 0; }
mutable char b[1024];
};

char const* va_stack_str(const char* format, va_list ap, const tmp_buf& b = tmp_buf())
{
vsnprintf(b.b, sizeof(b.b), format, ap);
return b.b;
}

char const* stack_str(const char* format, ...)
{
va_list ap;
va_start(ap, format);
const char* str = va_stack_str(format, ap);
va_end(ap);
return str;
}

int main()
{
printf("%s", stack_str("hello %s", "world"));
return 0;
}

该应用按预期工作,但通过 valgrind 运行它会提示未初始化的值

我的 valgrind 命令行是 valgrind --leak-check=full --track-origins=yes --quiet

Valgrind 输出:

==30513== Conditional jump or move depends on uninitialised value(s)
==30513== at 0x4E828F3: vfprintf (vfprintf.c:1661)
==30513== by 0x4E8B388: printf (printf.c:33)
==30513== by 0x400A73: main (main.cpp:28)
==30513== Uninitialised value was created by a stack allocation
==30513== at 0x4E80BF6: vfprintf (vfprintf.c:235)
==30513==
==30513== Syscall param write(buf) points to uninitialised byte(s)
==30513== at 0x4F233B0: __write_nocancel (syscall-template.S:81)
==30513== by 0x4EB0A82: _IO_file_write@@GLIBC_2.2.5 (fileops.c:1261)
==30513== by 0x4EB1F5B: _IO_do_write@@GLIBC_2.2.5 (fileops.c:538)
==30513== by 0x4EB3ADD: _IO_flush_all_lockp (genops.c:848)
==30513== by 0x4EB3C39: _IO_cleanup (genops.c:1013)
==30513== by 0x4E730FA: __run_exit_handlers (exit.c:95)
==30513== by 0x4E73194: exit (exit.c:104)
==30513== by 0x4E58ECB: (below main) (libc-start.c:321)
==30513== Address 0x4025000 is not stack'd, malloc'd or (recently) free'd
==30513== Uninitialised value was created by a stack allocation
==30513== at 0x4E80BF6: vfprintf (vfprintf.c:235)

tmp_buf 构造函数更改为 memset 整个缓冲区不会更改 valgrind 的输出

tmp_buf() { memset(b, 0, sizeof(b)); }

最佳答案

虽然我对 Valgrind 不是很熟悉,但我可以在您的代码中看到一个明显的问题,并且可以就 Valgrind 以这种方式提示的原因提供我最好的猜测。

一、问题:

函数 va_stack_str 返回一个指向参数 b 的成员 b 的指针,它的类型是 const tmp_buf&。因为此函数无法控制此参数引用的对象的生命周期,所以它返回一个指针,其有效性只能在调用它的完整表达式结束之前得到保证。在参数 b 由临时初始化的情况下(这正是 stack_str 使用它的方式),那么完整表达式的结尾恰好是返回指针有效。

函数stack_str接着将va_stack_str返回的指针保存到局部变量str中,然后返回。此时,调用 va_stack_str 的完整表达式已经结束,因此指针悬空 - 它指向在堆栈上分配但已被释放的缓冲区。

代码之所以有效,可能是因为缓冲区确实存在的那部分堆栈在读取时没有被覆盖,因此仍然包含以前缓冲区的内容。

为什么我认为 valgrind 发出“未初始化值”警告:

vfprintf 肯定会为局部变量分配一些堆栈空间,其中一些可能分配在与我们要求它打印的缓冲区相同的堆栈内存中。当 vfprintf 然后使用这个缓冲区(我们传递给它的那个)时,Valgrind 认为这个内存不是我们的原始缓冲区(已被释放),而是 的局部变量的地址vfprintf 已分配。

我的猜测是这些局部变量之一在 vfprintf 扫描我们传递给它的缓冲区以寻找终止 NULL 字符时未初始化。在这种情况下,它会检查指向它自己未初始化的局部变量的内存,这通常不会发生,因为 vfprintf 稍后会在它打算使用它之前对其进行初始化。 vfprintf 期望您将传递一个指向您已分配的缓冲区的指针,而不是一个最终指向它自己的局部变量的指针!

关于c++ - Valgrind 报告标准库中未初始化的值 (vfprintf.c),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25883551/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com