Valgrind - snprintf:条件跳转或移动取决于未初始化的值
Valgrind - snprintf : Conditional jump or move depends on uninitialised value(s)
通过 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
命令。此外,该数组包含行执行后的预期字符串。
Valgrind 的消息,
==9290== Conditional jump or move depends on uninitialised value(s)
是不言自明的:程序被观察到依赖于未初始化的内存来做出决定。在标准库函数中发生这种情况,很自然地假设函数参数有问题。由于您专门打印字符串,最可能的原因是其中一个字符串参数未终止。
事实上,至少有一个是。考虑这段代码:
#define TARGET "8.8.8.8"
[...]
strncpy(st_args->target, TARGET , sizeof(TARGET)-1);
为了安全起见,你搬起石头砸了自己的脚。 strncpy()
最多复制指定数量的字节,但它 不会 之后附加终止符。因此,其 Linux 手册页包含此警告:
Warning: If there is no null byte among the first n
bytes of src
, the string placed in dest
will not be null terminated.
您已确保该警告中描述的情况会发生——没有写入空终止符,分配给 st_args->target
的最后一个字节仍未初始化。
由于您小心地为整个字符串分配了足够的 space,包括终止符,所以 strncpy()
无论如何都是过大的。只需使用 strcpy()
。或者实际上,如果您的系统有 strdup()
或者您愿意编写一个实现,那么 strdup()
比 malloc()
+ strcpy()
.
干净得多
或者,如果您想使用 strncpy()
,那么最好通过在每个 strncpy()
调用的最后一个字节手动写入终止符来确保目标字符串终止目的地。在这种情况下,那将是
st_args->target[sizeof(TARGET)] = '[=12=]';
另请注意,您实际上分配的字节比您需要的多一个字节,因为 sizeof
字符串文字包含终止符。上面的代码是为实际的一字节太多分配编写的。
通过 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
命令。此外,该数组包含行执行后的预期字符串。
Valgrind 的消息,
==9290== Conditional jump or move depends on uninitialised value(s)
是不言自明的:程序被观察到依赖于未初始化的内存来做出决定。在标准库函数中发生这种情况,很自然地假设函数参数有问题。由于您专门打印字符串,最可能的原因是其中一个字符串参数未终止。
事实上,至少有一个是。考虑这段代码:
#define TARGET "8.8.8.8"
[...]
strncpy(st_args->target, TARGET , sizeof(TARGET)-1);
为了安全起见,你搬起石头砸了自己的脚。 strncpy()
最多复制指定数量的字节,但它 不会 之后附加终止符。因此,其 Linux 手册页包含此警告:
Warning: If there is no null byte among the first
n
bytes ofsrc
, the string placed indest
will not be null terminated.
您已确保该警告中描述的情况会发生——没有写入空终止符,分配给 st_args->target
的最后一个字节仍未初始化。
由于您小心地为整个字符串分配了足够的 space,包括终止符,所以 strncpy()
无论如何都是过大的。只需使用 strcpy()
。或者实际上,如果您的系统有 strdup()
或者您愿意编写一个实现,那么 strdup()
比 malloc()
+ strcpy()
.
或者,如果您想使用 strncpy()
,那么最好通过在每个 strncpy()
调用的最后一个字节手动写入终止符来确保目标字符串终止目的地。在这种情况下,那将是
st_args->target[sizeof(TARGET)] = '[=12=]';
另请注意,您实际上分配的字节比您需要的多一个字节,因为 sizeof
字符串文字包含终止符。上面的代码是为实际的一字节太多分配编写的。