So I've been teaching myself C, and in the hopes of learning how to properly manage memory from the beginning and write better code, I've been running Valgrind on everything. This has helped me with memory leaks, but I can't seem to get rid of this "Conditional jump or move depends on uninitialised value(s)/Uninitialised value was created by a heap allocation" situation, although I've narrowed it down to this block of code:
所以我一直在教自己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;
}
When I run Valgrind with ---track-origins=yes
, I get this output:
当我使用--- track-originins = 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)
This seems like a false positive to me, but I'm not confident enough in my own knowledge to write it off as such. Maybe I'm allocating wrong or using strncpy wrong? I'm not sure.
这对我来说似乎是一种误报,但是我对自己的知识不够自信地把它写下来。也许我分配错误或使用strncpy错误?我不确定。
Thanks in advance
提前致谢
3 个解决方案
#1
17
No, this is broken code.
不,这是破码。
You have a memory block with 3 uninitialized characters. Then you copy "12"
into it, and don't terminate. Beware of strncpy()
.
你有一个带有3个未初始化字符的内存块。然后将“12”复制到其中,并且不要终止。小心strncpy()。
I quote the documentation:
我引用文档:
The strncpy() function is similar, except that not more than n bytes of src are copied. Thus, if there is no null byte among the first n bytes of src, the result will not be null-terminated.
strncpy()函数类似,只是复制了不超过n个字节的src。因此,如果src的前n个字节中没有空字节,则结果将不会以空值终止。
Since there is no termination within the first 2 characters of the source, the destination is not terminated.
由于源的前2个字符内没有终止,因此目标不会终止。
#2
4
Idiomatic ways to use strcpy()
and strncpy()
:
使用strcpy()和strncpy()的惯用方法:
If you know that the buffer has space for the string plus the NUL terminator, you can use strcpy()
. This will probably use constants, or have checks in code (you should make sure the checks are right).
如果您知道缓冲区有字符串空间加上NUL终止符,则可以使用strcpy()。这可能会使用常量,或者在代码中进行检查(您应该确保检查是正确的)。
Otherwise, you can do:
否则,您可以这样做:
strncpy(dest, src, length);
dest[length - 1] = '\0';
which has the following disadvantages:
它有以下缺点:
- it can truncate strings.
- it is potentially inefficient, since it always fills
length
bytes.
它可以截断字符串。
它可能是低效的,因为它总是填充长度字节。
There is also OpenBSD's strlcpy()
.
还有OpenBSD的strlcpy()。
Any other use of strcpy()/strncpy()
is potentially suspicious, and you should look at them carefully.
strcpy()/ strncpy()的任何其他用法都可能存在疑问,您应该仔细查看它们。
Bottom line: avoid C string functions for anything moderately complex, try to use some library for dynamically allocated strings. Qmail/Postfix roll their own, GNU has obstacks.
结论:避免C字符串函数适用于任何中等复杂的函数,尝试使用一些库来动态分配字符串。 Qmail / Postfix自己滚动,GNU有顽固性。
#3
1
Your string has no terminator, so valgrind is probably right when it complains. Change:
你的字符串没有终止符,所以valgrind在抱怨时可能是正确的。更改:
strncpy(test, "123", 2);
to:
strcpy(test, "12");
#1
17
No, this is broken code.
不,这是破码。
You have a memory block with 3 uninitialized characters. Then you copy "12"
into it, and don't terminate. Beware of strncpy()
.
你有一个带有3个未初始化字符的内存块。然后将“12”复制到其中,并且不要终止。小心strncpy()。
I quote the documentation:
我引用文档:
The strncpy() function is similar, except that not more than n bytes of src are copied. Thus, if there is no null byte among the first n bytes of src, the result will not be null-terminated.
strncpy()函数类似,只是复制了不超过n个字节的src。因此,如果src的前n个字节中没有空字节,则结果将不会以空值终止。
Since there is no termination within the first 2 characters of the source, the destination is not terminated.
由于源的前2个字符内没有终止,因此目标不会终止。
#2
4
Idiomatic ways to use strcpy()
and strncpy()
:
使用strcpy()和strncpy()的惯用方法:
If you know that the buffer has space for the string plus the NUL terminator, you can use strcpy()
. This will probably use constants, or have checks in code (you should make sure the checks are right).
如果您知道缓冲区有字符串空间加上NUL终止符,则可以使用strcpy()。这可能会使用常量,或者在代码中进行检查(您应该确保检查是正确的)。
Otherwise, you can do:
否则,您可以这样做:
strncpy(dest, src, length);
dest[length - 1] = '\0';
which has the following disadvantages:
它有以下缺点:
- it can truncate strings.
- it is potentially inefficient, since it always fills
length
bytes.
它可以截断字符串。
它可能是低效的,因为它总是填充长度字节。
There is also OpenBSD's strlcpy()
.
还有OpenBSD的strlcpy()。
Any other use of strcpy()/strncpy()
is potentially suspicious, and you should look at them carefully.
strcpy()/ strncpy()的任何其他用法都可能存在疑问,您应该仔细查看它们。
Bottom line: avoid C string functions for anything moderately complex, try to use some library for dynamically allocated strings. Qmail/Postfix roll their own, GNU has obstacks.
结论:避免C字符串函数适用于任何中等复杂的函数,尝试使用一些库来动态分配字符串。 Qmail / Postfix自己滚动,GNU有顽固性。
#3
1
Your string has no terminator, so valgrind is probably right when it complains. Change:
你的字符串没有终止符,所以valgrind在抱怨时可能是正确的。更改:
strncpy(test, "123", 2);
to:
strcpy(test, "12");