使用valgrind检查内存泄漏-SinoDB
valgrind是一款被广泛使用的内存泄漏检测工具,可以用来检测程序是否有非法使用内存的问题,例如访问未初始化的内存、访问数组时越界、忘记释放动态内存等问题,本次查漏就使用了这款软件,这类工具市面上有很多,以前也有使用过其他的工具检测,大的问题就是给了过多的检测信息,没有成功帮忙解决过内存泄漏问题,当然也可能是使用方法不对,总之对此类工具的感觉就是高深却无用。本次在同事的极力安利下尝试了下,改变了我的看法。
下面记录了一次成功检测内存泄漏的过程:
- Valgrind Linux安装
1. 下载,wget ftp://sourceware.org/pub/valgrind/valgrind-3.13.0.tar.bz2
2. 编译安装
./configure --prefix=/usr/local/bin
make;make install
以上请使用root账号安装。
- valgrind使用
执行valgrind --leak-check=full bin/SqltSnifferService.exe
更深入使用请自行查看帮助选项。
1. 测试用例
1018 50 bytes in 2 blocks are definitely lost in loss record 185 of 292
1018 at 0x4A069EE: malloc (vg_replace_malloc.c:270)
1018 by 0x4A06B62: realloc (vg_replace_malloc.c:662)
1018 by 0x43E817: rowdata_header_decode (sqlt_data.c:1924)
1018 by 0x43ABD8: data_row_output (sqlt_data.c:334)
1018 by 0x438B48: data_row_out_handle (sqlt_trace.c:2569)
1018 by 0x435C6B: select_decode (sqlt_trace.c:882)
1018 by 0x436EAF: execute_decode (sqlt_trace.c:1664)
1018 by 0x437199: exesql_decode (sqlt_trace.c:1721)
1018 by 0x4350A4: tt_decode (sqlt_trace.c:587)
1018 by 0x434C02: sqlt_trace_run (sqlt_trace.c:415)
1018 by 0x404194: DeSqltStream (pds-sqlt.c:398)
1018 by 0x444719: CsTcpFlushAck (cstcp.c:1284)
1018
1018 422 bytes in 2 blocks are definitely lost in loss record 219 of 292
1018 at 0x4A069EE: malloc (vg_replace_malloc.c:270)
1018 by 0x43EB1A: code_set_conv (sqlt_data.c:2050)
1018 by 0x436CE3: execute_decode (sqlt_trace.c:1621)
1018 by 0x437199: exesql_decode (sqlt_trace.c:1721)
1018 by 0x4350A4: tt_decode (sqlt_trace.c:587)
1018 by 0x434C02: sqlt_trace_run (sqlt_trace.c:415)
1018 by 0x404194: DeSqltStream (pds-sqlt.c:398)
1018 by 0x444719: CsTcpFlushAck (cstcp.c:1284)
1018 by 0x44257A: CsTcpStream (cstcp.c:561)
1018 by 0x442DAC: CsTcpHandler (cstcp.c:742)
1018 by 0x441422: CsPcapPacketHandler (cspcap.c:496)
1018 by 0x4E7015D: pcap_offline_read (savefile.c:380)
输出信息显示有两处地方存在内存泄漏,并且给出了调用关系,仔细核查后,发现代码的确存在问题。
done:
if(!rowdata_head.null_col_arr && rowdata_head.arr_size >0) {
free(rowdata_head.null_col_arr);
rowdata_head.null_col_arr = NULL;
rowdata_head.arr_size = 0;
rowdata_head.null_col_num = 0;
}
应该要将条件改成if(rowdata_head.null_col_arr && rowdata_head.arr_size >0)
if (sql_cmd_find(&st->sql_info, &sql_cmd->sql_id, &sql_cmd)) {
/*sql_cmd be push*/
sql_cmd = NULL;
sql_str = NULL;
}
结合上下文,此处的sql_str不能设置为NULL。
2. 测试用例
31636 Invalid read of size 1
31636 at 0x43ECC3: sqlt_u16_read (sqlt_msg.c:65)
31636 by 0x43AB9A: data_row_output (sqlt_data.c:323)
31636 by 0x438B46: data_row_out_handle (sqlt_trace.c:2577)
31636 by 0x4387AB: bind_decode_091d (sqlt_trace.c:2359)
31636 by 0x4381BC: bind_decode (sqlt_trace.c:2183)
31636 by 0x436DB4: execute_decode (sqlt_trace.c:1636)
31636 by 0x437197: exesql_decode (sqlt_trace.c:1729)
31636 by 0x4350A4: tt_decode (sqlt_trace.c:587)
31636 by 0x434C02: sqlt_trace_run (sqlt_trace.c:415)
31636 by 0x404194: DeSqltStream (pds-sqlt.c:398)
31636 by 0x444729: CsTcpFlushAck (cstcp.c:1284)
31636 by 0x44258A: CsTcpStream (cstcp.c:561)
31636 Address 0x68b4c74 is 0 bytes after a block of size 1,620 alloc'd
31636 at 0x4A06BE0: realloc (vg_replace_malloc.c:662)
31636 by 0x43A0FD: tt_packet_push (tt_packet.c:190)
31636 by 0x434B4E: sqlt_trace_run (sqlt_trace.c:376)
31636 by 0x404194: DeSqltStream (pds-sqlt.c:398)
31636 by 0x444729: CsTcpFlushAck (cstcp.c:1284)
31636 by 0x44258A: CsTcpStream (cstcp.c:561)
31636 by 0x442DBC: CsTcpHandler (cstcp.c:742)
31636 by 0x441432: CsPcapPacketHandler (cspcap.c:496)
31636 by 0x4E7015D: pcap_offline_read (savefile.c:380)
31636 by 0x4E62B8F: pcap_loop (pcap.c:427)
31636 by 0x441629: CsPcapLoop (cspcap.c:587)
31636 by 0x42EEB3: ProjectLoop (pds-framework.c:406)
31636
此处信息显示读取了的数据,问题代码如下。
if(sqlt_u16_read(msg) != 0x0c0d) {
break;
}
msg只剩下一个byte,而sqlt_u16_read(msg)是读取2个byte,这可能也会造成越界读取错误,甚至程序crash。
代码修改为
if(msg_len >1 && sqlt_u16_read(msg) != 0x0c0d) {
break;
}
以上代码修改编译后,重新运行,现在的信息如下 。
31636 LEAK SUMMARY:
31636 definitely lost: 0 bytes in 0 blocks
31636 indirectly lost: 0 bytes in 0 blocks
31636 possibly lost: 0 bytes in 0 blocks
31636 still reachable: 1,840,003 bytes in 15,234 blocks
31636 suppressed: 0 bytes in 0 blocks
31636 Reachable blocks (those to which a pointer was found) are not shown.
31636 To see them, rerun with: --leak-check=full --show-reachable=yes
现在没有错误提醒了。
通过以上介绍可以看出这款软件的强大,次使用时,并没有发现特别有用的信息。可能的原因是测试用例的问题,需要将程序编译成debug版,即需要开启-g编译选项。
相关文章