【问题标题】:Could valgrind complaint about uninitialized values be a false positive?valgrind 对未初始化值的投诉会是误报吗?
【发布时间】:2011-09-14 19:49:12
【问题描述】:

所以我一直在自学 C,并希望从一开始就学习如何正确管理内存并编写更好的代码,我一直在所有东西上运行 Valgrind。这帮助我解决了内存泄漏问题,但我似乎无法摆脱这种“条件跳转或移动取决于未初始化的值/未初始化的值是由堆分配创建的”情况,尽管我已经缩小了范围到这个代码块:

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

int main()    
{  
    char* test = (char*) malloc(3);
    strncpy(test, "123", 2);
    printf("%s\n", test);
    free(test);
    return 0;
}

当我使用 ---track-origins=yes 运行 Valgrind 时,我得到以下输出:

==91702== Conditional jump or move depends on uninitialised value(s) 
==91702==    at 0x100011507: strlen (mc_replace_strmem.c:282)
==91702==    by 0x1000AA338: puts (in /usr/lib/libSystem.B.dylib)
==91702==    by 0x100000EFA: main (valgrind_test.c:10)
==91702==  Uninitialised value was created by a heap allocation
==91702==    at 0x100010345: malloc (vg_replace_malloc.c:236)
==91702==    by 0x100000EEA: main (valgrind_test.c:8)

这对我来说似乎是一个误报,但我对自己的知识没有足够的信心将其注销。也许我分配错误或使用 strncpy 错误?我不确定。

提前致谢

【问题讨论】:

  • 你的字符串没有终结符,所以 valgrind 抱怨时可能是对的。
  • 在这里使用 snprintf 会更好恕我直言。 snprintf(test, 3, "123");

标签: c valgrind


【解决方案1】:

不,这是损坏的代码。

您有一个包含 3 个未初始化字符的内存块。然后将"12" 复制到其中,并且不要终止。当心strncpy()

我引用the documentation

strncpy() 函数类似,只是复制的 src 不超过 n 个字节。因此,如果 src 的前 n 个字节中没有空字节,则结果不会以空值结尾。

由于源的前 2 个字符内没有终止符,因此目标没有终止。

【讨论】:

  • 添加注释永远不会有坏处:永远不要使用strncpy
  • 似乎我没有仔细阅读手册页 - 我认为 strncpy 会用空值填充目标字符串的其余部分。只有当 n 比源字符串长时才会发生这种情况。
  • @pivotal:对。除了n,它还能如何知道目标字符串的长度? @ninjalj:是的,如果有人还在使用它们。 :-) 但这是一个非常晦涩的用法,我发现告诉初学者“从不”通常比尝试解释固定大小的记录格式更安全。
  • @R.. 您建议从现有字符串中提取子字符串的替代方法是什么?
  • 我个人建议不要使用除memcpysnprintf 之外的任何函数来编写字符串。后者可以使用 %.*s 说明符很好地提取长度为 N 的子字符串,如果您在使用它时遵循简单的正确模式,它是 100% 安全的。如果您使用memcpy,则必须对长度和空终止采取自己的预防措施。 (顺便说一句,strncat 也可以做你想做的事。)
【解决方案2】:

您的字符串没有终止符,因此 valgrind 在它抱怨时可能是正确的。变化:

strncpy(test, "123", 2);

到:

strcpy(test, "12");

【讨论】:

    【解决方案3】:

    strcpy()strncpy() 的惯用用法:

    如果你知道缓冲区有空间容纳字符串加上 NUL 终止符,你可以使用strcpy()。这可能会使用常量,或者在代码中进行检查(您应该确保检查是正确的)。

    否则,你可以这样做:

    strncpy(dest, src, length);
    dest[length - 1] = '\0';
    

    有以下缺点:

    • 它可以截断字符串。
    • 它可能效率低下,因为它总是填充length 字节。

    还有OpenBSD的strlcpy()

    strcpy()/strncpy() 的任何其他用途都可能存在可疑之处,您应该仔细查看它们。

    底线:避免 C 字符串函数用于任何中等复杂的东西,尝试使用一些库来动态分配字符串。 Qmail/Postfix 自己滚,GNU 有obstacks

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-15
      • 1970-01-01
      • 1970-01-01
      • 2014-03-21
      • 1970-01-01
      • 2012-02-15
      相关资源
      最近更新 更多