通过valgrind启动程序后,我收到以下消息:
==9290== Conditional jump or move depends on uninitialised value(s)
==9290== at 0x4E82A03: vfprintf (vfprintf.c:1661)
==9290== by 0x4EA9578: vsnprintf (vsnprintf.c:119)
==9290== by 0x4E8B531: snprintf (snprintf.c:33)
==9290== by 0x400820: _function (in /home/snp/prog/TEST)
==9290== by 0x4006D5: start (in /home/snp/prog/TEST)
==9290== by 0x40085C: main (in /home/snp/prog/TEST)
==9290== Uninitialised value was created by a heap allocation
==9290== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9290== by 0x400715: init (in /home/snp/prog/TEST)
==9290== by 0x400857: main (in /home/snp/prog/TEST)
以下代码重现错误:
#include <net/if.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#define TARGET "8.8.8.8"
#define DEVICE "eth0"
static int _function(void);
struct remote
{
char *target;
char device[IFNAMSIZ];
};
struct remote * st_args;
int start(void)
{
return (_function());
}
int init(void)
{
st_args = malloc (sizeof (struct remote));
if (st_args == NULL)
return (-1);
st_args->target = malloc (sizeof (TARGET)+1);
if (st_args->target == NULL)
{
free (st_args);
return (-1);
}
strncpy(st_args->target, TARGET , sizeof(TARGET)-1);
strncpy(st_args->device, DEVICE, IFNAMSIZ-1);
return 0;
}
void stop(void)
{
if (st_args != NULL)
{
free (st_args->target);
free (st_args);
}
}
static int _function(void)
{
char cmd[256];
memset(cmd, 0, sizeof(cmd));
snprintf(cmd, sizeof(cmd), "ping -I %s %s", st_args->device, st_args->target);
return 0;
}
int main(int argc, char **argv)
{
init();
start();
stop();
return 0;
}
我仍然不明白这个问题,为什么valgrind不接受snprintf
命令。此外,该数组包含行执行后的预期字符串。
答案 0 :(得分:2)
Valgrind的留言,
== 9290 ==条件跳转或移动取决于未初始化的值
是相当不言自明的:观察到程序依赖于未初始化的内存来做出决定。尽管在标准库函数中发生了它,但很自然地假设函数参数有问题。由于您专门打印字符串,最可能的原因是其中一个字符串参数未被终止。
事实上,至少有一个是。请考虑以下代码:
#define TARGET "8.8.8.8"
[...]
strncpy(st_args->target, TARGET , sizeof(TARGET)-1);
为了安全起见,你已经开始自责。 strncpy()
最多复制指定的字节数,但之后不会附加终结符。因此,其Linux手册页包含此警告:
警告:如果
n
的前src
个字节中没有空字节,则放置在dest
中的字符串将不会以空值终止。< / p>
您已确保发生该警告中描述的情况 - 未写入空终止符,并且为st_args->target
分配的最后一个字节仍未初始化。
由于您要小心为完整的字符串分配足够的空间,包括终结符,strncpy()
无论如何都是过度的。只需使用strcpy()
即可。或者,如果您的系统有strdup()
或者您愿意编写实现,那么strdup()
比malloc()
+ strcpy()
更清晰。
或者,如果您想使用strncpy()
,那么最好通过手动将终结符写入最后一个字节来确保通过跟进每个strncpy()
调用来终止目标字符串。目的地。在这种情况下,那将是
st_args->target[sizeof(TARGET)] = '\0';
另请注意,您实际分配的字节数多于您需要的字节数,因为sizeof
字符串文字包含终止符。上面的代码是为实际的一个字节太多的分配而编写的。