内存问题有两种:内存损坏 memory corruption(crash) 和 内存泄漏 memory leak
memory crash:发生在修改了未知内存后,程序访问了这部分受损的内存,可能会导致程序crash掉或者发生不可预知的结果。
发生在:
memory leak:动态分配的内存没有释放,或者分配太多内存跑不到free的地方
可能会引起:
Malloc debug 是一种native层内存问题的方法。他可以帮助我们定位memory crash, memory leak, UAF的问题。如果检测到任何的问题,会通过日志的方式呈现出来。
Malloc Debug 开启后会在替换掉原来的内存分配函数(加Hook层),在分配的内存数据前加Header,并且可以根据option添加前后的front_guard和rear_guard。
Header |
---|
front_guard |
allocation data |
rear_guard |
Header组成如下:
struct Header { uint32_t tag; //标记内存是否释放 void* orig_pointer; //指向Header的起始地址 size_t size: //allocation data的大小 size_t usable_size; //已使用大小 }__attribute__((packed)); //取消内存对齐
在Header中有个tag标记内存是否释放:0x1ee7d00d为可以使用, 0x1cc7dccd为已经释放
根据这些前后的固定填充,如果这些固定的字节发生了变化可以判断这部分内存被踩了。
相关的option:
通过 dump + gdb 查看内存信息。
malloc debug 对内存调试有帮助,但是不方便,你只能确定发生了这些问题,但是不能在第一现场拦下,也不能确定问题发生的时间。
ASAN:Address Sanitizer Mechanism
把进程虚拟地址分成两部分,一部分是正常使用的main application memory,一部分是Shadow memory影子内存,两者占比8:1。
shadow memory用来记录main allocation memory的状态。
这个debug方法可以在第一现场拦下
但是ASAN只能标记内存能否访问,没有标记内存的所有者。
log里面会把出错的report打印出来
开启方式:make结束以后再执行一次相应的命令
HWASAN:Hardware ASAN
需要在64位机器上,并且要内核4.14以上才支持
可以标记内存的所有者,在指针的最高2byte做了tag
HWASAN可以检测的bug与ASAN相同:
与ASAN的改动:main application memory 与 shadow memory 的占比为16:1
然后在可用内存地址的最高2个byte(16个bit)加了个tag标记内存所有者
在shadow memory如果对应的main memory的16个byte都可以访问,则shadow memory存放tag的值,如果只有部分byte可以访问,则记录0~15可访问的byte,然后将tag的值记录到main memory最后一个不可访问的byte上。
开启方式:可以用一次make指令然后加上编译选项即可: make SANITIZE_TARGET=hwaddress
如何确认已开启?通过ps | grep process找到进程号,然后cat /proc/pid/maps|grep hwasan
缺点:因为tag只有8bit,最多只有256个不同的tag,有概率会分配2个相同的tag
用于内核层的debug工具,与Malloc Debug类似采用前后插guard的方式
对应与用户空间的ASAN工具。也是采用shadow memory来检测内存,占可用内存的1/8,会带来内核内存空间的开销。
开启方式:在.config配置文件中指定 CONFIG_KASAN_GENERIC=y
KASAN有三种,GENERIC KASAN, Software Tag-based KASAN, Hardware Tag-based KASAN
cat /proc/meminfo 查看内存使用情况
cat /proc/pid/maps 查看进程的内存映射情况(比如使用malloc后会出现[heap]区