基于日志分析的软件测试示例1——内存泄漏
王树钿
wangshudian#gmail.com,2011-4-8
引言
4月3日对上一篇介绍的LogFileAnalysisTool规定的日志格式做了修改,考虑到文件名、行号、函数名、时间戳等乃用户关注的上下文信息,不应在格式上约束,为此换用CONTEXT字段,具体内容由用户填入,如下:
1)修改前日志格式:
FILE:文件名,LINE:行号,SM:对象名,OBJID:对象ID,EVENT:事件
2)修改后日志格式:
OBJSM:对象状态机,OBJID:对象ID, EVENT:事件, CONTEXT:上下文信息
下面内容介绍如何利用基于状态机的日志分析工具来对软件开发中常见的内存泄漏问题进行预测试。
第一步,对象状态分析
以malloc和free为例,我们关心的对象是内存管理模块,先给对象状态机取个名字,美其名曰:memmng,那么对象状态转换配置文件名为memmng.ini,文件内容如下所示:
如果觉得上面脚本不够直观,请看对应的状态转换表:
--------|------|-----|
|from/on| E0 | E1 |
|-------|------|-----|
| S0 | S1 | S-1 |
|-------|------|-----|
| S1 | S-2 | S0 |
|-------|------|-----|
第二步,用Hook方式记录事件日志
对于嵌入式软件,由于板子内存和FLASH空间大小有限,存储日志数量难以保证数据完整性,为避开这个问题,使用日志分析方法检查软件缺陷有两种方案:一种是创建一个低优先级任务对队列中日志记录进行在线分析;一种是在PC上做ST,将日志文件保存在硬盘上,然后进行日志文件分析。本节简单描述方案二的设计和实现。
首先,PC版的软件如何记录日志?我知道的方法有两种:
第一种,用宏。如果允许修改功能代码,那么建议用宏的方式。例如:
第二种,用Hook函数。适用于不允许修改功能代码的情况。例如:
malloc的钩子函数记录日志如下:
LogFile.txt
第三步,查看日志分析报告
运行日志分析程序后,生成日志分析报告,如下:
ReportFile.txt
注:CallerAddr指malloc函数的调用者下一条指令的地址。
第四步,定位问题所在函数(或文件和行号)
知道了malloc调用者下一条指令地址,即可定位问题所在函数。我知道的方式有两种:
方式一,反汇编。例如,执行批处理脚本dumpbin_LogFAT.bat:
然后在生成的反汇编文件disasm.txt中搜索日志分析报告出错指令地址47dd0b,找到所在函数,如下:
?be_tested_module_run@@YAXXZ:
0047DD00: 55 push ebp
0047DD01: 8B EC mov ebp,esp
0047DD03: 51 push ecx
0047DD04: 6A 05 push 5
0047DD06: E8 08 A1 FF FF call @ILT+11790(_malloc)
0047DD0B: 83 C4 04 add esp,4
方式二,Map文件。如下:
1、配置生成Map文件。以VS2005 IDE为例,配置步骤:属性页---->链接器---->调试---->生成映射文件选“是(/MAP)”---->映射文件名选编辑,然后点击右下角的宏,选择$(ProjectName),添加后缀.map,即$(ProjectName).map。
2、在map文件中找到距离指令地址最近的前一个地址,即为缺陷所在函数。例如我们已知指令地址0x47dd0b,那么在map文件中可以找到小于它且离它最近的地址0047dd00,即be_tested_module_run就是出问题的函数:
0002:00008d00 ?be_tested_module_run@@YAXXZ 0047dd00 f gtest_LogFAT.obj
注:后续如果有必要可以做一个根据指令地址查找函数名的工具将第三、四步合并。