valgrind使用经验两则
今天在Ubuntu上面用valgrind运行了BinSpec,出现了一堆警告,摸索了一阵子才把警告都消除掉,下面是我遇到的两个问题。
第一类警告:
==4016== Invalid read of size 1 ==4016== at 0x0804a36c: ignore_wac (within /home/bg5sbk/Code/Labs/BinSpec/bin/bs) ==4016== by 0x0804a491: next_token (within /home/bg5sbk/Code/Labs/BinSpec/bin/bs) ==4016== by 0x0804b36f: bs_parse (within /home/bg5sbk/Code/Labs/BinSpec/bin/bs) ==4016== by 0x0804c39c: main (within /home/bg5sbk/Code/Labs/BinSpec/bin/bs) ==4016== Address 0x41e83c7 is 0 bytes after a block of size 527 alloc'd ==4016== at 0x04028876: malloc (vg_replace_malloc.c:236) ==4016== by 0x0804c4e9: file_get_contents (within /home/bg5sbk/Code/Labs/BinSpec/bin/bs) ==4016== by 0x0804c31b: main (within /home/bg5sbk/Code/Labs/BinSpec/bin/bs)
这一类警告相对比较好找,已经提示出问题的函数是ignore_wac,内存是在file_get_contents函数分配的,并提示在xxx地址之后是0字节,意思就是越界读取了。
察看一下代码,在最后一次next_token函数调用的时候的确会越界读取,但是最终原因是file_get_contents返回的不是C语言的\0结尾的字符串,所以最终修改的是file_get_contents函数的内存分配,多分配一个末尾字节,这个警告便消失了。
第二类警告:
==4038== Conditional jump or move depends on uninitialised value(s) ==4038== at 0x040ae410: vfprintf (vfprintf.c:1620) ==4038== by 0x040b51de: printf (printf.c:35) ==4038== by 0x08049a5b: bs_print_pkg_list (within /home/bg5sbk/Code/Labs/BinSpec/bin/bs) ==4038== by 0x08049a43: bs_print_pkg_list (within /home/bg5sbk/Code/Labs/BinSpec/bin/bs) ==4038== Uninitialised value was created by a heap allocation ==4038== at 0x04028876: malloc (vg_replace_malloc.c:236) ==4038== by 0x08049566: bs_def_new (within /home/bg5sbk/Code/Labs/BinSpec/bin/bs) ==4038== by 0x0804acf3: parse_def (within /home/bg5sbk/Code/Labs/BinSpec/bin/bs) ==4038== by 0x0804b22b: parse_pkg (within /home/bg5sbk/Code/Labs/BinSpec/bin/bs)
这类警告的信息比较直观,但是却比较不好排查,反复检查bs_def_new函数的结构体初始化都没有发现问题,最后才定位到这个函数中的字符串复制代码,原来的代码是这样的:
char *name2 = (char *)malloc(name_len + 1); def->name = strncpy(name2, name, name_len); def->name_len = name_len;
因为按man提供的帮助信息,strncpy会把目标字符串中过长的部分自动填充\0,所以这里实际上不会有问题,但是valgrind会认为name2这个内存块分配后没初始化,最后加上bzero函数后警告消失,最终代码是这样:
size_t name2_len = name_len + 1; char *name2 = (char *)malloc(name_len + 1); bzero(name2, name2_len); def->name = strncpy(name2, name, name_len); def->name_len = name_len;