C Valgrind警告:我应该认真对待吗
背景: 我有一个模拟fgets(character,2,fp)的小例程,除了它从字符串而不是流中获取字符。newBuff是作为参数传递的动态分配字符串,字符声明为C Valgrind警告:我应该认真对待吗,c,valgrind,overlap,strcpy,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中的重叠(0x419b
char character[2]
例行程序:
character[0] = newBuff[0];
character[1] = '\0';
strcpy(newBuff, newBuff+1);
strcpy在读取每个字符时复制信息丢失
问题:Valgrind确实警告过我
此活动“源和目标”
strcpy中的重叠(0x419b818,
0x419b819)”
我应该担心这个警告吗?如果源和目标重叠,
strcpy()的行为正式未定义
memcpy手册页中有一条建议:
函数的作用是:将n个字节从内存区域s2复制到内存区域s1。如果s1和s2重叠,则行为未定义。s1和s2可能重叠的应用程序应改用memmove(3)
是--strcpy
的行为仅在源和目标不重叠的情况下定义。你可以考虑<代码>斯特伦< /> >和<代码> MeMaTest< /Cord>。 <是的,你应该担心。C标准规定,strcpy的行为是源对象和目标对象重叠时的行为。未定义的行为意味着它有时可能会工作,或者可能会失败,或者它可能看起来成功了,但在程序的其他地方显示失败。标准可能没有指定这些缓冲区重叠时会发生什么。是的,valgrind
对此的抱怨是正确的
实际上,您很可能会发现您的strcpy
是按从左到右的顺序复制的(例如while(*dst++=*src++);
),这不是问题。但它仍然不正确,并且在与其他C库一起运行时可能会出现问题
一种正确的书写方法是:
memmove(newBuff, newBuff+1, strlen(newBuff));
因为memmove
被定义为处理重叠。(虽然在这里您将遍历字符串两次,一次检查长度,一次复制。我还选择了一个快捷方式,因为strlen(newBuff)
应该等于strlen(newBuff+1)+1,这是我最初编写的内容。)是的,您还应该担心您的函数在病理学上的性能不好(O(n^2)
用于应为O(n)
的任务。每次读取一个字符时,将字符串的全部内容向后移动一个字符是一种巨大的时间浪费。相反,您应该只保留一个指向当前位置的指针并递增该指针
如果您发现自己需要memmove
或同等功能(在重叠的缓冲区之间复制),则几乎总是表明存在设计缺陷。通常情况下,这不仅仅是实现中的缺陷,而是接口中的缺陷。答案是肯定的:对于某些编译器/库实现,我猜是最新的,最终会得到一个虚假的结果。请参阅以获取示例。无论如何实现,行为都是未定义的。标准中明确规定了这一点。strcpy
在缓冲区重叠时给出了未定义的行为memcpy
的作用与此相同,但在其他方面与此无关。好的,我的strcpy本地手册页不包含此警告,但memcpy页包含此警告。C标准中唯一接受指向重叠内存区域的指针进行读写的函数是memmove
和wmemmove
。对于其他所有内容(包括snprintf
!),行为未定义。即使顺序是从左到右的,也可能由于展开/重新排序和大于字节单位的复制而出现问题。我会考虑使用<代码> StcPy非常不安全,并且可能在同一库的不同版本之间出现盈亏平衡,甚至不同编译器的不同版本。我同意,尤其是关于大于字节单位的观点。我只想说清楚,我同意代码不正确,应该修改。