查看原文
其他

深入理解内存泄漏检查kmemleak

bang Linux阅码场 2022-12-14

作者简介

bang,linux内核爱好者,目前就职于杭州某安防公司,主要从事于SOC的bring up及驱动开发,喜欢分析linux内核内存管理和调度子系统。



1.概述


内存泄漏是我们工作中经常遇到的问题,比如随着业务的持续运行,系统中可用内存在快速减少,导致某个重要的业务进程被OOM kill掉了。内存泄漏往往都是很严重的问题,尤其是内核态的内存泄漏,危害更大。每次泄漏一块内存,该块内存就成为一个黑洞,如果是严重的内核态内存泄漏,系统将很快变的无法正常使用,通常需要重启设备或者服务器才能解决问题。我们肯定不希望这种事情发生,那就需要想办法把内存泄漏提前暴露在测试环境中。要解决内存泄漏问题,首先需要了解内存泄漏的特点。内存泄漏分为用户态的内存泄漏和内核态的内存泄漏,我们本文主要关注的是内核态的内存泄漏。工作中比较常见的内存泄漏按照发生泄漏的频率可以划分以下几种类型:


  • 1、一次性内存泄漏,只在初始化过程中或某一次条件触发产生的内存泄漏。

  • 2、偶发性内存泄漏,在某种条件下偶尔触发产生的内存泄漏。

  • 3、频发性内存泄漏,内存泄漏点被频繁的触发。


对于频发性内存泄漏我们有比较多的调试手段去定位,比如我们可以先通过/proc/meminfo信息大致确定下内存泄漏发生在哪个模块中,再通过其他手段进一步定位。如果观察到vmalloc异常,可以通过/proc/vmallocinfo信息分析定位。如果观察到slab内存异常,可以通过slabinfo/sys/kernel/slab/*/alloc_callsfree_calls去辅助定位问题。而对于一次性的或者偶发性的内存泄漏确很难去通过/proc/meminfo信息快速分析定位,且大量的一次性或偶发性内存泄漏,同样给系统造成额外的内存压力。而本文介绍的kmemleak工具为各种类型的内存泄漏提供了一种检测方法。


2.原理


kmemleak(kernel memory leak detector)是检测内核空间的内存泄漏的调试工具。检测对象是memblock_allockmallocvmallockmem_cache_alloc等函数分配的内存块,该内存块由struct kmemleak_object来描述(简称为object)。kmemleak的实现原理非常简单,通过暴力扫描内存(假定内存中存放的都是指针,以ARM64为例,每次扫描8个字节),如果找不到指向起始地址或者内存块任何位置的指针,则分配的内存块被认为是孤立的。这意味着内核可能无法将分配内存块的地址传递给释放函数,因此该内存块被视为内存泄漏。内存块(object)有3种颜色,分别为黑色、白色、灰色, 通过count和min_count区分不同颜色的object。


黑色: min_count = -1,表示被忽略的object,此object不包含对别人的引用,也不会存在内存泄漏,比如代码段会标记为黑色。


白色: count < min_count,孤立的object,没有足够的引用指向这个object,一轮扫描结束后被认为泄漏的内存块。


灰色: min_count = 0,表示不是孤立的object,即不存在内存泄漏的object,如代码中主动标记object为灰色,防止误报(如data、bss、ro_after_init)。或者count >= min_count,对该object有足够的指针引用,认为不存在内存泄漏的内存块。


具体检测步骤如下:


  • 1、通过struct kmemleak_object(简称为object)描述kmallocvmallockmem_cache_alloc等函数申请的内存块,记录申请内存的起始地址,大小、call trace等信息。同时把object加入到红黑树object_tree_root和双向链表object_list中,红黑树中的key值为内存块的起始地址。


  • 2、遍历双向链表object_list,把所有的objectcount计数清0,即在新的一轮扫描前,尽可能的把能复位成白色的object标记为白色。然后判断object是否是灰色(默认databssro_after_init段会被标记为灰色),如果是灰色的object则把object加入到灰色链表gray_list中。


  • 3、扫描内存中可能存放指针的内存区域(per-cpu段、struct page的内容、内核栈、灰色链表),根据挂在红黑树中所有的object的地址范围进行对比。如果有指针指向某一个object(指向该object的起始地址或者指向object地址范围内),会把object对应的count字段增加1,如果object变成灰色,则会把object加入到灰色链表中。


  • 4、扫描object_list中的白色对象的object,判断object所描述的地址范围的内容的crc值是否发生变化,如果发生变化,则同样把object加入到灰色链表gray_list中。说明通过间接的方式访问了object描述的地址范围,不是内存泄漏,减少误报。


  • 5、重新扫描灰色链表,因为步骤4中,可能有些白色的object加入到了灰色链表中,需要重新扫描。


  • 6、经过上述一系列的扫描,剩余白色的object就是可疑的内存泄漏点。 

3.数据结构


3.1、kmemleak_object


struct kmemleak_object描述一段通过memblock_allockmallocvmallockmem_cache_alloc等函数分配的内存块。此内存块会加入到红黑树object_tree_root和双向链表object_list中。


struct kmemleak_object {    raw_spinlock_t lock;    unsigned int flags;         struct list_head object_list;    struct list_head gray_list;    struct rb_node rb_node;         atomic_t use_count;    unsigned long pointer;    size_t size;    unsigned long excess_ref;    int min_count;    int count;    u32 checksum;    struct hlist_head area_list;    unsigned long trace[MAX_TRACE];    unsigned int trace_len;    unsigned long jiffies;      /* creation timestamp */    pid_t pid;          /* pid of the current task */    char comm[TASK_COMM_LEN];   /* executable name */};



lock:spinlock锁用于保护当前的object对象。


flags:object的状态标志位。有以下状态标志位:


  • OBJECT_ALLOCATED:表示已经分配的内存块的状态标志。在创建object的时候,会置上此标记,在释放object的时候,清除此标记。


  • OBJECT_REPORTED:表示经过一轮内存扫描之后,把有内存泄漏风险的object的flags置上OBJECT_REPORTED,然后用户可以通过cat /sys/kernel/debug/kmemleak获取有内存泄漏风险的object。


  • OBJECT_NO_SCAN:表示不去扫描此内存块。kmemleak为了减少误报和漏报,通过封装好的接口设置内存块是否需要扫描,如果不需要扫描则flags置上OBJECT_NO_SCAN标志。


  • OBJECT_FULL_SCAN:表示当内存不足分配scan_area失败的时候,把当前的object标记为OBJECT_FULL_SCAN,表示此objcet全部扫描,不再是局部扫描


object_list:通过该字段把objec添加到object_list链表中。


gray_list:通过该字段把object添加到gray_list链表中。


rb_node:通过该字段把object添加到object_tree_root的红黑树中。


use_count:object使用计数。通过get_object增加计数,put_object减少计数,当use_count = 0时释放该object。


pointer:object的起始地址。


size:object的大小。


excess_ref:具体见kmemleak_vmalloc函数实现。


min_count:指向内存块的最少指针个数。如果小于该值,说明有内存泄漏的嫌疑。


count:扫描到的指向内存块的指针总数,和min_count配合使用。


checksum:内存块的CRC校验和。


area_list:如果area_list链表为NULL,则以object的pointer为起始地址和size为大小的地址范围扫描。如果不为NULL,以area_list链表中的kmemleak_scan_area节点的start和size为地址范围扫描。一个object描述的内存块可能被分割为多个kmemleak_scan_area区域,所有的kmemleak_scan_area通过node节点添加到area_list为头的链表中。


trace:保存创建object的stack trace的地址。


trace_len:表示stack trace的实际深度,最大深度为MAX_TRACE(16)。


jiffies:创建object时的jiffies。


pid:表示创建objcet的pid号。


comm:创建object的进程名。


3.2、kmemleak_scan_area


struct kmemleak_scan_area内存块的扫描区域描述符。为了降低误报,限制所属的object描述的内存块的扫描范围,对object描述的地址范围划分为不同的kmemleak_scan_area区域进行扫描。


/* scanning area inside a memory block */struct kmemleak_scan_area { struct hlist_node node; unsigned long start; size_t size;};


3.3、全局变量


object_list:新创建的object会挂入到全局的objcet_list链表中。


gray_list:如果object不存在内存泄漏的风险,会把object加入到gray_list链表中,表示不存在内存泄漏风险的object。


object_tree_root:为了加快查询速度,新创建的object,不仅会加入到object_list全局链表中,同时会加入到object_tree_root为根的红黑树,红黑树的key值为object的起始地址。


min_addr:所有object中最小的起始地址。有可能最小起始地址的object已经不在object链表中或者红黑树中。目的是为了对检测的地址进行简单的过滤。


max_addr:所有object中最大的结束地址。有可能最大结束地址的object已经不在object链表中或者红黑树中。目的是为了对检测的地址进行简单的过滤。


jiffies_last_scan:开始扫描时候的jiffies。


jiffies_min_age:为了减少误报,避免报告最近分配的object。因为最近分配的object的指针有可能临时存放在cpu的寄存器中。默认值为MSECS_MIN_AGE(5s)。通过unreferenced_object函数可以看出上报有内存泄漏风险的object,需要在此扫描周期开始的T0之前创建object。而T0之后到扫描结束之间创建的object,要在下一个周期进行扫描检测。



static bool unreferenced_object(struct kmemleak_object *object){ return (color_white(object) && object->flags & OBJECT_ALLOCATED) && time_before_eq(object->jiffies + jiffies_min_age, jiffies_last_scan);}

jiffies_scan_wait:两次扫描的时间间隔SECS_SCAN_WAIT默认为60s。


4.kmemleak代码实现


4.1、kmemleak_init


void __init kmemleak_init(void){#ifdef CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF if (!kmemleak_skip_disable) { /* 1 */ kmemleak_disable(); return; }#endif /* register the data/bss sections */ /* 2 */ create_object((unsigned long)_sdata, _edata - _sdata, KMEMLEAK_GREY, GFP_ATOMIC); create_object((unsigned long)__bss_start, __bss_stop - __bss_start, KMEMLEAK_GREY, GFP_ATOMIC); /* only register .data..ro_after_init if not within .data */ if (&__start_ro_after_init < &_sdata || &__end_ro_after_init > &_edata) create_object((unsigned long)__start_ro_after_init, __end_ro_after_init - __start_ro_after_init, KMEMLEAK_GREY, GFP_ATOMIC);}


  • 1、如果定义了CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF宏或者通过cmdline设置为kmemleak=off,则默认关闭kmemleak。如果cmdline中设置kmemleak=on,则表示默认开启kmemleak功能。如果没有定义CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF宏,则默认是开启kmemleak功能。


  • 2、创建data段、bss段、.data..ro_after_init段对应的object


思考


问题一为什么不直接静态扫描这些段的内容,而是需要通过object的方式进行管理?


:因为这些section的某些区域可能被动态的释放(如bss段),如果静态扫描可能产生page fault,进一步产生kenrel panic。所以这里采用创建object的方式去扫描bss段,同时把此object标记为灰色,因为这个object描述的内存块不存在内存泄漏。当需要释放bss段的某些区域的时候通过调用kmemleak_free_part函数动态的把bss段进行分割成不同的新的object。(扣除释放的区域)


问题二:为什么需要判断.data..ro_after_init段的范围?


:.data..ro_after_init段表示在内核初始化过程中这个段是可读写的,在初始化完成之后把该段修改为只读。不同的架构的.data..ro_after_init段位于不同的区域,有的直接属于data段,有些会归到rodata段中。如果在data段里,则无需再创建object,如果不在data段内,则需要创建对应的object。


4.2、create_object

 



创建一个object对象,并对object的成员进行初始化,同时把object加入到红黑树和双向链表中。假设新创建的object起始地址为10,如下图所示:

 


4.3、delete_object_full/delete_object_part


 

delete_object_full删除整个object,把object从红黑树中和双向链表中删除,同时释放object对应的内存。


 

delete_object_part切割object对象,把完整的object进行切割,有4种情况:


  • 1、左边删除,只留右边的区域,以右边区域为内存块,创建一个新的object

  • 2、右边删除,只留左边的区域,以左边区域为内存块,创建一个新的object

  • 3、刚好完全删除整个object描述的区域,等价于delete_object_full

  • 4、删除中间区域,留两边区域,创建两个新的object

 


put_object递减object的引用计数,如果引用计数为0,则把object进行释放。


4.4、创建object的api接口分析


api接口函数

分析

kmemleak_alloc

kmemleak_alloc直接调用create_object函数,ptr、size、min_count由使用者指,如kmalloc、slab/slub/slob函数。min_count为1,表示至少有一处指针指向申请的内存块。

kmemleak_alloc_percpu

kmemleak_alloc_percpu函数需要对每个cpu都调用一次create_object函数,其中min_count为0,表示percpu区域的内存不存在内存泄漏,即默认为灰色object。

kmemleak_vmalloc

kmemleak_vmalloc函数首先调用create_object创建一个新的object,但min_count为2,即表示最少有两处指针指向内存块才能说明vmalloc申请的内存块没有产生泄漏。同时把area->addr设置到object->excess_ref字段中。

kmemleak_alloc_phys

kmemleak_alloc_phys函数的起始地址为物理地址,主要用于memblock机制中memblock_alloc申请的内存块。且min_count为0,表示memblock_alloc申请的内存块默认为灰色object,不存在内存泄漏,只对内存块内容扫描。


思考:


1、kmemleak_vmalloc中为什么min_count等于2?

 


从图中我们可以看出,struct vm_struct中的addr字段指向vmalloc申请的内存块,strct vmap_area中的va_start字段也指向了vmalloc申请的内存块。同时我们可以知道vmalloc的返回值肯定也保存在某个变量中。理论上至少有3处指针指向了vmalloc的内存块的起始地址,为什么min_count为2?因为strct vmap_area中va_start字段在alloc_vmap_area函数中通过kmemleak_scan_area(&va->rb_node, SIZE_MAX, gfp_mask)函数给过滤掉了,所以min_count为2。


2、kmemleak_vmalloc中为什么要把area->addr设置到vm_struct内存块对应的object的excess_ref字段中?


答:考虑这样一种场景,vmalloc申请的内存块的起始地址,并没有被直接引用,而是通过一个全局指针struct vm_struct *tmp 间接引用。我们可以得到如下信息:


1、tmp可以通过vm_struct间接的访问vmalloc的区域。

2、vm_struct的指针同时也被保存在vmap_area中。

通过上面信息我们可以知道扫描全局指针tmp的时候会把vm_struct内存块对应的object加入到灰色链表中。扫描vmap_area的时候遍历到vm_struct指针的时候,发现指针对应的object已经加入到灰色链表中,不做处理,然后在扫描vm_struct所在内存块对应的object的灰色链表的时候,扫描到addr字段的时候,把addr对应的vmalloc区域的object的count++。此时count (1) < min_count(2)会报内存泄漏。其实不是内存泄漏,因为我们可以通过tmp指针间接的找到vmalloc的addr。所以如果我们发现vm_struct对应的object已经变为灰色了,我们需要确定下vm_struct中addr字段是否在红黑树中能找到对应的object?如果能找到,则把addr对应的object的count++。因此对于vmalloc申请的区域,我还需要检查对vm_struct引用次数。如果大于等于2次,我们也不认为是内存泄漏。


4.5、 kmemleak_scan_thread


kmemleak_scan_thread函数实现,整个扫描流程的逻辑见下面流程图:



 

4.6、scan_gray_list


scan_gray_list扫描灰色链表。

 


  • 1、从灰色链表中获取一个object


  • 2、如果object对应的灰色链表不为NULL,则扫描当前的object,扫描完成后,获取下一个object,然后把当前的object从灰色链表中删除,同时递减引用计数,因为在加入灰色链表的时候会调用get_object增加引用计数。


4.7、scan_object


scan_object扫描object的内容。

 


  • 1、如果object的flags中OBJECT_NO_SCAN被置位了,则不去扫描此object对应的内存块。kmemleak_not_leak、kmemleak_ignore等函数会把object的flags置上OBJECT_NO_SCAN,无需扫描此object的内容,可防止误报。


  • 2、如果object已经被释放了,自然也不能扫描。


  • 3、如果object->area_list为NULL或者OBJECT_FULL_SCAN被置位,说明object的内存块内容需要被全部扫描。


  • 4、如果object->area_list不为NULL且OBJECT_FULL_SCAN未置位,则扫描object区域的部分内容,只扫描添加到object->area_list中指定的区域(通过kmemleak_scan_area函数指定object内存块的地址扫描范围)。


4.8、scan_block


scan_block扫描指定内存地址范围内容。


 

  • 1、如果扫描的指针不在最大最小值范围内,则跳过此指针。

  • 2、在红黑树中查找是否有满足条件的object,条件为pointer在[object->pointer, object->pointer + size)范围内,如果有则返回对应的object。


  • 3、如果没找到,则跳过此指针。

  • 4、如果pointer指针找到的object是自己,则也跳过此指针。

  • 5、如果已经是灰色的object就不再更新。同时获取object的excess_ref字段,这个字段主要用于vmalloc场景。

  • 6、如果不是灰色的object,则更新object。如果是白色,则对object的count++。如果变成灰色,则增加引用计数同时把object添加到灰色链表中。

  • 7、用于vmalloc场景,通过vm_struct间接访问vmalloc的返回地址。经过扫描发现指针指向的内存块对应的object为vm_struct区域且此object已经变成灰色,则需要检查下vm_struct中addr对应的内存块是否在红黑树中,如果在,则需要把addr对应内存块的object的count++。如果变成灰色,则增加引用计数同时把addr对应的object添加到灰色链表中,防止因引用了vm_struct而产生的误报。


5.false positives/negatives


5.1、false positives(误报)


误报不是内存泄漏,而报告为内存泄漏。

可能产生误报的原因:


  • 1、通过固定偏移映射的方式访问虚拟地址。如kasan_module_alloc函数对影子区域的内存块的申请是通过__vmalloc_node_range,而使用是通过非影子区的地址来访问,即通过kasan_mem_to_shadow(addr)函数获取影子区址间接访问。这时候需要通过kmemleak_ignore函数告诉kmemleak这不是内存泄漏。同时kmemleak_ignore还能保证影子区的内容不会被扫描,因为影子区域并不存放指针。


include/linux/kasan.hstatic inline void *kasan_mem_to_shadow(const void *addr){return (void *)((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT) + KASAN_SHADOW_OFFSET;}


  • 2、没有保存虚拟地址而保存物理地址或者struct page等。


如hsc_msg_alloc函数,保存的是buf对应的page。virt_to_page(buf)


drivers/hsi/clients/hsi_char.cstatic inline struct hsi_msg *hsc_msg_alloc(unsigned int alloc_size) { void *buf; buf = kmalloc(alloc_size, GFP_KERNEL); sg_init_one(msg->sgt.sgl, buf, alloc_size); /* Ignore false positive, due to sg pointer handling */ kmemleak_ignore(buf); return msg;}sg_init_onesg_set_buf(sg, buf, buflen)sg_set_page(sg,virt_to_page(buf), buflen,offset_in_page(buf))


  • 3、没有直接保存虚拟地址而是保存虚拟地址或上某个变量。


arch/s390/kernel/nmi.cstatic int __init nmi_init(void){ unsigned long origin, cr0, size; ... origin = (unsigned long) kmem_cache_alloc(mcesa_cache, GFP_KERNEL); kmemleak_not_leak((void *) origin); ... S390_lowcore.mcesad = origin | mcesa_origin_lc; ...return 0;}


  • 4、指针存放的区域不会被扫描,如vmap函数映射的区域,没有对应的object


kernel/bpf/ringbuf.cstatic struct bpf_ringbuf *bpf_ringbuf_area_alloc({pages = bpf_map_area_alloc(array_size, numa_node);...rb = vmap(pages, nr_meta_pages + 2 * nr_data_pages, VM_ALLOC | VM_USERMAP, PAGE_KERNEL);kmemleak_not_leak(pages);rb->pages = pages;...}


  • 5、其他情况。


综上可以看出产生误报的原因是没有直接保存申请出来的虚拟地址,而是

保存虚拟地址某种映射关系得到的值,或者存放指针的内存块无法被

扫描(如vmap区域),而产生误报。


如何解决误报?


可以通过kmemleak_ignorekmemleak_not_leak等函数显示告诉kmemleak这不是内存泄漏。kmemleak_ignore表示object不存在内存泄漏,且也不会扫描内存块的内容。kmemleak_not_leak表示object不存在内存泄漏,但是会扫描内存块的内容。


5.2、false negatives(漏报)


漏报是内存泄漏,但是没有报告出来。

比如扫描的地址存放的是数据而不是指针,但是能在红黑树中找到对应的

object,并把此object加入到灰色链表中,这样就产生了漏报。


如何解决漏报?


可以通过kmemleak_ignore、 kmemleak_scan_area kmemleak_no_scan and kmemleak_erase函数解决漏报问题,不同场景使用不同的函数。


6.使用方法


使用kmemleak可以很方便地检测出内核态的内存泄露。可以用于设备驱动程序或内核模块的评估。虽然kmemleak的扫描算法存在漏报和误报的可能,但是并不影响我们的使用。因为这个工具的目的是为了给我们进一步分析提供线索,并不需要绝对精确,小概率的误报和漏报并不影响这个工具的实用性。


6.1、常用功能宏


内容

CONFIG_DEBUG_KMEMLEAK

在kernel hacking中打开CONFIG_DEBUG_KMEMLEAK宏,表示内核支持kmemleak功能。

CONFIG_DEBUG_KMEMLEAK_AUTO_SCAN

如果开启CONFIG_DEBUG_KMEMLEAK_AUTO_SCAN宏,则会触发自动扫描,调用start_scan_thread函数进行扫描。

CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF

如果定义了CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF宏或者通过cmdline设置为kmemleak=off,则默认关闭kmemleak。如果cmdline中设置kmemleak=on,则表示默认开启kmemleak功能。如果没有定义CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF宏,则默认是开启kmemleak功能。


6.2、具体使用方法


  • 1、挂载debugfs

mount -t debugfs nodev /sys/kernel/debug/


  • 2、内核线程每10分钟(默认情况下)扫描一次,并打印找到的可疑的内存泄漏object。也可以在任意时刻执行kmemleak的内存扫描。

echo scan > /sys/kernel/debug/kmemleak


  • 3、详细的输出信息通过/sys/kernel/debug/kmemleak获取。

cat /sys/kernel/debug/kmemleak


6.3、其它参数说明


参数

内容

off

禁用kmemleak。不再跟踪内存分配和释放。一旦禁用,就不能再次开启。

stack=on

启用线程栈区域的扫描。默认是on。

stack=off

禁用线程栈区域的扫描。

scan=on

开启kmemleak内核线程的自动扫描。默认为on。

scan=off

停止kmemleak内核线程的自动扫描。

scan=<s>

设置kmemleak线程执行扫描时间间隔。单位为秒,默认为600s(10分钟)。0s表示停止自动扫描。

scan

手动触发扫描,立即扫描。

clear

清除检测出的数据,即清除之前判断为内存泄露的object信息,会把这些object标记为KMEMLEAK_GREY,并不会把object从红黑树和双向链表中删除,不在/sys/kernel/debug/kmemleak中显示,只是不显示,可以使用dump参数进行确定。在使用kmemleak前清除没有关系的信息时使用。

dump=<addr>

显示addr对应object信息。


详细的使用方法参考kenrel文档Documentation/dev-tools/kmemleak.rst。


7.案例


从kmemleak.rst文档中摘取的log。


# cat /sys/kernel/debug/kmemleak unreferenced object 0xffff89862ca702e8 (size 32): comm "modprobe", pid 2088, jiffies 4294680594 (age 375.486s) hex dump (first 32 bytes): 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk. backtrace: [<00000000e0a73ec7>] 0xffffffffc01d2036 [<000000000c5d2a46>] do_one_initcall+0x41/0x1df [<0000000046db7e0a>] do_init_module+0x55/0x200 [<00000000542b9814>] load_module+0x203c/0x2480 [<00000000c2850256>] __do_sys_finit_module+0xba/0xe0 [<000000006564e7ef>] do_syscall_64+0x43/0x110 [<000000007c873fa6>] entry_SYSCALL_64_after_hwframe+0x44/0xa9


通过kmemleak report的输出信息,我们可以获取如下信息:


  • 1、产生泄漏内存块对应的object的起始地址为0xffff89862ca702e8,

泄漏的大小为32个字节。


  • 2、进程名为modprobe,pid为2088,创建object时的jiffies为375.486s。

  • 3、泄漏内存块的前32字节数据。

  • 4、泄漏点的backtrace信息。

 


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存