C++ 使用容器注释包装器检测内存缓冲区溢出不起作用

问题描述 投票:0回答:1

我正在尝试使用容器注释包装器强制 ASan 检测从堆栈分配内存的指针的缓冲区溢出。 下面是我的例子

#include <sanitizer/asan_interface.h>
#include <iostream>
#include <array>

constexpr size_t N = 32;

class A {
public:
    int x;
};

int main() {
    char buf [sizeof(A)];
    A *a = new (buf) A;
    __sanitizer_annotate_contiguous_container(buf, buf + sizeof(A), buf, buf + sizeof(A));
    a->~A();
    a[sizeof(A) + 64].x = 4;
    std::cout << a[sizeof(A) + 64].x << std::endl;
}

为什么消毒剂没有检测到内存违规?

演示

c++ memory-management buffer-overflow address-sanitizer placement-new
1个回答
0
投票

首先,你似乎错误地使用了

__sanitizer_annotate_contiguous_container
。它的签名是:

void __sanitizer_annotate_contiguous_container(const void *beg_p,
                                               const void *end_p,
                                               const void *old_mid_p,
                                               const void *new_mid_p)

因此,当您发布

a
时,您希望将其标记为

__sanitizer_annotate_contiguous_container(buf, buf + sizeof(A), buf + sizeof(A), buf);

其次,ASAN 不报告堆栈溢出的原因似乎是 ASAN 仅将超出帧边界的 3 个影子字节(24 个实际字节)标记为不可寻址,这可以通过查看轻松找到错误时的影子字节:

shadow memory layout

https://godbolt.org/z/Mxz7qxhfo

在这里,您在帧开始之后的

(sizeof(A) + 64) * sizeof(A)
= 272 字节或帧结束之后的 264 字节处对堆栈进行寻址,因此不会引发错误。如果您在堆上分配
buf
,因为 ASAN 在堆分配上标记了更宽的红区,您会发现正确报告了内存违规,但原因是“堆溢出”,而不是“容器溢出”。

© www.soinside.com 2019 - 2024. All rights reserved.