Valgrind警告:我应该认真对待它

时间:2011-01-28 00:48:07

标签: c valgrind overlap strcpy

背景: 我有一个模仿fgets(character, 2, fp)的小例程,除了它从字符串而不是流中获取字符。 newBuff是动态分配的字符串,作为参数传递,字符声明为char character[2]

例程:

character[0] = newBuff[0];

character[1] = '\0';

strcpy(newBuff, newBuff+1);

strcpy在从中读取每个字符时复制信息丢失。

  

问题:Valgrind警告我   这项活动,“来源和目的地   strcpy重叠(0x419b818,   0x419b819)”。

我应该担心这个警告吗?

6 个答案:

答案 0 :(得分:11)

可能标准没有规定当这些缓冲区重叠时会发生什么。是的,valgrind抱怨这是正确的。

实际上,您很可能会从左到右(例如strcpy)按顺序找到您的 while (*dst++ = *src++);副本,并且这不是问题。但它仍然不正确,并且在与其他C库一起运行时可能会出现问题。

一种标准正确的写法方式是:

memmove(newBuff, newBuff+1, strlen(newBuff));

因为memmove被定义为处理重叠。 (虽然在这里你最终会遍历字符串两次,一次检查长度和一次复制。我也采用了一个快捷方式,因为strlen(newBuff)应该等于strlen(newBuff+1)+1,这是我最初写的。)

答案 1 :(得分:5)

是的,您还应该担心您的函数在性能方面有不良影响(O(n^2)应该是O(n)的任务。每次读取一个角色时,都会通过角色移回字符串的全部内容,这是一个巨大的浪费时间。相反,你应该只保留一个指向当前位置的指针并增加该指针。

您发现自己需要memmove或等效的情况(在重叠的缓冲区之间复制)几乎总是表示设计缺陷。通常,它不仅仅是实现中的缺陷,而是在界面

答案 2 :(得分:4)

是 - 仅在源和目标不重叠时才定义strcpy的行为。您可以考虑使用strlenmemmove的组合。

答案 3 :(得分:4)

是的,你应该担心。 C标准声明当源和目标对象重叠时strcpy的行为为undefined。未定义的行为意味着它可能有时会起作用,或者它可能会失败,或者它可能看起来成功但会在程序的其他地方出现失败。

答案 4 :(得分:3)

如果源和目标重叠,则strcpy()的行为正式未定义。

来自memcpy的联机帮助页提出了一个建议:

  

memcpy()函数将n个字节从存储区s2复制到存储区s1。如果s1和s2重叠,则行为未定义。 s1和s2可能重叠的应用程序应使用memmove(3)代替。

答案 5 :(得分:2)

答案是肯定的:对于某些编译器/库实现,我猜最新的,你最终会得到一个虚假的结果。有关示例,请参阅How is strcpy implemented?