内存管理——内存调试技术

2022/9/1 5:24:13

本文主要是介绍内存管理——内存调试技术,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

常见内存问题

内存问题有两种:内存损坏 memory corruption(crash) 和 内存泄漏 memory leak

memory crash:发生在修改了未知内存后,程序访问了这部分受损的内存,可能会导致程序crash掉或者发生不可预知的结果。

发生在:

  • 使用未初始化的内存
  • 使用不存在的内存,空指针
  • 使用了超出分配的内存,数组越界
  • 堆内存管理错误,UAF,double free

memory leak:动态分配的内存没有释放,或者分配太多内存跑不到free的地方

可能会引起:

  • 程序功能正常,但是引起系统性能卡顿,apk越来越慢
  • 内存泄漏过多导致申请内存不足malloc mmap失败,造成OOM等其他问题

内存调试技术

Malloc Debug

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为已经释放

  • front_guard 由 0xaa 填充的8个byte组成
  • rear_guard 由 0xbb 填充的8个byte组成

根据这些前后的固定填充,如果这些固定的字节发生了变化可以判断这部分内存被踩了。

相关的option:

  • guard 可以开启front_guard和rear_guard,做越界检查
    • 不会在写超的时候第一现场拦下来,只有free的时候才可以检查
  • free_track 可以检查UAF
    • 当free后不会归还系统,而是保存到List,填充内容为0xef。如果后面发现这部分内容不是0xef的话就表示这部分内存UAF了
    • 但是这样会有额外内存开销,系统压力会比较大。
  • backtrace 追踪每次分配信息
    • 会大大减慢内存分配的速度。如果因为开启这个选项导致系统运行太慢,需要减少采集的帧数。

通过 dump + gdb 查看内存信息。
malloc debug 对内存调试有帮助,但是不方便,你只能确定发生了这些问题,但是不能在第一现场拦下,也不能确定问题发生的时间。

ASAN

ASAN:Address Sanitizer Mechanism

把进程虚拟地址分成两部分,一部分是正常使用的main application memory,一部分是Shadow memory影子内存,两者占比8:1。

shadow memory用来记录main allocation memory的状态。

这个debug方法可以在第一现场拦下

但是ASAN只能标记内存能否访问,没有标记内存的所有者。

log里面会把出错的report打印出来

开启方式:make结束以后再执行一次相应的命令

HWASAN

HWASAN:Hardware ASAN

需要在64位机器上,并且要内核4.14以上才支持

可以标记内存的所有者,在指针的最高2byte做了tag

HWASAN可以检测的bug与ASAN相同:

  • 堆栈buffer溢出
  • UAF,double free
  • 栈溢出

与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

Slub Debug

用于内核层的debug工具,与Malloc Debug类似采用前后插guard的方式

KASAN

对应与用户空间的ASAN工具。也是采用shadow memory来检测内存,占可用内存的1/8,会带来内核内存空间的开销。

开启方式:在.config配置文件中指定 CONFIG_KASAN_GENERIC=y

KASAN有三种,GENERIC KASAN, Software Tag-based KASAN, Hardware Tag-based KASAN

memory leak

cat /proc/meminfo 查看内存使用情况
cat /proc/pid/maps 查看进程的内存映射情况(比如使用malloc后会出现[heap]区



这篇关于内存管理——内存调试技术的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程