内存越界是一类既麻烦又难解的bug.
因为内存的越界发生了之后,
1.踩到致命内存,马上崩溃,只知道被踩的内存区域,并不知道是怎么被踩的
2.踩了多次,才踩到致命内存,崩溃,同样的,只知道被踩的内存区域,并不知道是怎么被踩的
3.踩了几次,通过连锁反应,才踩到致命内存,这个就更麻烦了。
目前成熟的debug方法有两种。
1.内存一旦越界,马上打印调用栈。
这是valgrind的做法。
优点是,不用重编文件,就可以debug.
内存越界,马上打印,不存在滞后
缺点是,每一条的内存访问都要确认是否越界(通过分析汇编语句的方法),设计原理上就是严重损耗性能。
因为是分析汇编语句,所以一定程度上也会存在误报的情况。
2.内存越界踩到的内存,被free的时候,打印调用栈。
(分配内存的时候,在内存段的前后填充一些常量,同时记录下是谁分配的内存。free的时候check常量是否被改,就可以判断内存是否被踩。
如果被踩,打印出是谁分配的内存,就可以回溯了)
这是libc malloc debug的做法。
优点是,不用重编文件,就可以debug,同时不怎么损耗性能。
缺点是, 如果被踩的内存没有free,或者还没有free,已经非法访问崩溃了,这个时候就没法debug了。
从设计原理上看,是一种滞后的判断方法,虽然被踩,等到free的时候,才检测到。
还有一个地方,libc debug无法对内部static链接libc的方式进行检测,因为是在基于系统libc的基础上debug,
所以如果没有链接使用系统libc就会无法加载,valgrind就没有这个问题,因为是基于汇编语言分析的。
总结如下: 1.valgrind方法: 实时检测内存越界,对应的损耗性能。
2.malloc debug方法: 当free的时候,检测内存越界,对应的存在滞后性,不能实时甚至有可能无法检测到。
滞后检测内存越界,对应的可能无法分析。
类似于中断跟轮询的差异。
注意:尽管您仍可以使用 Valgrind 对 Android 进行调试,但 Android 平台开发者会改用 AddressSanitizer。在未来的版本中,Valgrind 将从平台中移除。
Android新版本后会采用asan工具。这个工具可能也是采用的valgrind的实时检测,不过需要重编代码。
没有使用过,待补充。
asan工具: https://source.android.com/devices/tech/debug/asan
valgrind工具: https://source.android.com/devices/tech/debug/valgrind