• Postgresql中检测内存越界或use after free的简便方法


    1 使用场景

    在Postgresql的内存管理模块中,最常用的aset.c提供的内存池实现,该实现提供了两个非常实用的开关来解决常见的内存越界问题:

    memdebug.c

     *	About CLOBBER_FREED_MEMORY:
     *
     *	If this symbol is defined, all freed memory is overwritten with 0x7F's.
     *	This is useful for catching places that reference already-freed memory.
     *
     *	About MEMORY_CONTEXT_CHECKING:
     *
     *	Since we usually round request sizes up to the next power of 2, there
     *	is often some unused space immediately after a requested data area.
     *	Thus, if someone makes the common error of writing past what they've
     *	requested, the problem is likely to go unnoticed ... until the day when
     *	there *isn't* any wasted space, perhaps because of different memory
     *	alignment on a new platform, or some other effect.  To catch this sort
     *	of problem, the MEMORY_CONTEXT_CHECKING option stores 0x7E just beyond
     *	the requested space whenever the request is less than the actual chunk
     *	size, and verifies that the byte is undamaged when the chunk is freed.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    简单总结如下:

    • CLOBBER_FREED_MEMORY:
      • 如果定义了这个符号,所有释放的内存都会被覆盖为0x7F。这对于捕捉引用已释放内存的地方非常有用。
    • MEMORY_CONTEXT_CHECKING:
      • 由于我们通常将请求的大小舍入到下一个2的幂,所以在请求的数据区域之后通常会有一些未使用的空间。因此,如果有人犯了常见的错误,超出了他们请求的范围,问题可能会被忽视…直到更换平台后,没有这种空间未使用空间,导致内存越界使用的问题才被发现。

    其实这两个宏在打开USE_ASSERT_CHECKING的使用就默认会生效。所以建议configure时记得打开enable_cassert。

    /*
     * Define this to cause pfree()'d memory to be cleared immediately, to
     * facilitate catching bugs that refer to already-freed values.
     * Right now, this gets defined automatically if --enable-cassert.
     */
    #ifdef USE_ASSERT_CHECKING
    #define CLOBBER_FREED_MEMORY
    #endif
    
    /*
     * Define this to check memory allocation errors (scribbling on more
     * bytes than were allocated).  Right now, this gets defined
     * automatically if --enable-cassert or USE_VALGRIND.
     */
    #if defined(USE_ASSERT_CHECKING) || defined(USE_VALGRIND)
    #define MEMORY_CONTEXT_CHECKING
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2 原理

    2.1 MEMORY_CONTEXT_CHECKING

    下面讲讲这两宏的原理,也比较简单:

    正常我们申请内存都是会向上对齐到2的幂上,比如申请5个字节实际上会分配8个字节出来,但是你只应该使用5个字节。
    在这里插入图片描述
    但是如果你内存越界访问到第六个字节后,实际上是不会发生任何破坏的,因为这第六个字节也没有人会用,释放时也不可能发现。这就造成了隐患(这类问题都比较难差会有奇怪的逻辑报错)。

    如果打开MEMORY_CONTEXT_CHECKING宏后:

    在这里插入图片描述

    2.2 CLOBBER_FREED_MEMORY

    还有use after free的场景,因为在pfree时,内存块中的内容不会立即被覆盖或重写,很可能发生上面已经free了,但后面还能正常用的场景,在某些串行逻辑下,貌似一直都不会出现问题,这也埋下了隐患(这类问题都比较难差会有奇怪的逻辑报错)。

    打开CLOBBER_FREED_MEMORY后,释放时会调用wipe_mem将内存覆盖成0X7F

    static inline void
    wipe_mem(void *ptr, size_t size)
    {
    	VALGRIND_MAKE_MEM_UNDEFINED(ptr, size);
    	memset(ptr, 0x7F, size);
    	VALGRIND_MAKE_MEM_NOACCESS(ptr, size);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    后面aset不会对0x7F做任何检查逻辑,因为没准你的数据就全是0x7F。但是memset后,肯定会将pfree的地址的数据立即覆盖掉,让后面使用者能尽早发现问题(看到一堆0x7F就知道是用了free后的地址了)。

  • 相关阅读:
    SSM和SpringBoot整合
    scala解析命令行参数详解
    Vue3.0安装与构建项目
    SwiftUI Swift 内功之 Swift 中的属性观察者 didSet 与 willSet
    2023 年 12 款最佳免费 PDF 阅读器
    Docker与虚拟化技术浅析第一弹之docker与Kubernetes
    139. 单词拆分 dp
    一网打尽异步神器CompletableFuture
    synchronized的锁策略及优化过程
    【leetcode42-----距离顺序排列矩阵单元格】
  • 原文地址:https://blog.csdn.net/jackgo73/article/details/132884701