调优过程
前提条件
- 服务器和操作系统正常运行。
- PC端已经能够SSH远程登录。
- 下载并编译example_00,并且要求:
- 编译完成的程序需要在GCC 4.9及以上版本的系统环境中运行。
- 必须使用 -fsanitize=address 选项.。
- 必须使用 -g 选项 。
- 可选择使用-fsanitize-recover=address选项,修复部分程序执行错误,以得到更完整的越界信息 。
- 可选择使用 -fno-omit-frame-pointer 选项,以得到更容易理解的调用栈信息 。
- 可选择 -O1 或者更高的优化级别编译例如:gcc -fsanitize=address -fno-omit-frame-pointer -O1 -g use-after-free.c -o use-after-free
- 该功能需要使用libasan.so,请确保/usr/lib64或/usr/local/lib64路径下存在该库文件。
- 环境上鲲鹏DevKit系统诊断工具已经安装完成。
操作步骤
- 创建内存诊断任务。
在左侧系统诊断区域单击系统诊断后面的
。
图1 创建内存越界任务 - 查看诊断结果。
查看内存越界结果,发生了堆缓存访问溢出异常,结合信息,对照源码文件example_00.c,分析原因是buffer1 malloc(100)成功后,内存空间中并没有字符串结束符标志\0,所以使用printf格式化输出%s时,会导致在buffer1的内存空间中寻找不到结束符,从而基于原先的内存空间继续寻址,导致数组越界访问,发生堆缓存访问溢出,继续分析源码,发现memset(buffer1, 'A', 99)之后同样使用printf格式化输出%s,所以此处也应该设置\0,同样的,buffer2也存在类似情况,一并修改。
图2 内存越界诊断结果图3 example_00.c源码 - 修改越界语句。
根据越界点文件名和行号,修改越界语句,重新编译后使用内存诊断工具重新进行测试。
图4 修改example_00.c源码 - 再次创建内存越界诊断并查看结果。图5 内存越界诊断结果
查看内存越界结果,发生了释放后越界,结合信息,对照源码文件example_00.c,分析原因是17行已经释放了变量buffer1(free(buffer1)),21行又打印该变量,继续分析,26、33行也打印了buffer1,删除这些打印后重新编译后使用内存诊断工具重新进行测试。
图6 修改example_00.c源码 - 再一次创建内存越界诊断并查看结果。图7 优化后的内存越界诊断结果
重新测试后发现example_00应用已经没有内存越界了,但是通过刚才的阅读源码,细心的读者会发现,变量buffer2在程序退出前并没有free掉,回到环境上手动执行example_00验证。
图8 执行验证图9 修改example_00.c源码 - 重新编译后,在环境上手动执行example_00验证。图10 执行验证
父主题: 内存越界调优实践