如何检测无效读取(使用代码而不是 valgrind)

How to detect invalid reads (using code not valgrind)

提问人:MIA 提问时间:1/14/2023 最后编辑:MIA 更新时间:1/14/2023 访问量:111

问:

假设你像这样分配了一个指向 char 的指针

char *ptr = malloc(10 * sizeof(char))

如果这个 ptr 被传递给另一个函数而没有传递它的大小,我们是否可以检测到 ptr[10] 正在读取不属于这个指针的内存。

我知道如果我使用 valgrind,我会得到无效读取,但我想编写一个代码以在发生这种情况时抛出异常。

C++ 管理 malloc 动态内存分配

评论

0赞 sklott 1/14/2023
在这种情况下,您需要使用相应的类型。要么是标准的,要么是你自己写的或在互联网上找到的东西。普通指针没有任何其他信息。std::array<char, 10>std::vector<char>
0赞 PIRIQITI 1/14/2023
你为什么不想通过尺寸?甚至操作系统也会跟踪在返回的地址之后分配了多少字节,如果不是这样,函数应该如何知道哪些块要返回给操作系统?malloc()free()
0赞 Alan Birtles 1/14/2023
不,c++ 标准不跟踪内存使用情况,大多数没有特殊调试标志的实现也不跟踪内存使用情况
0赞 user4581301 1/14/2023
不是很有效。您可以过度分配金丝雀值并将其添加到开头和结尾,但当您检查金丝雀时,可能已经为时已晚。最好使用内置边界检查的数据结构。
0赞 user4581301 1/14/2023
旁注:在 C++ 中分配动态存储时,最后伸手去 和 family dead。一般的优先顺序是容器智能指针和 、 和 朋友和 。mallocnew[]delete[]mallocfree

答:

1赞 Henrique Bucher 1/14/2023 #1

实现此目的的一种可能方法是使用页面防护。虽然这很昂贵,但可以让您在发生异常时获得异常。

#include <cstdint>
#include <cstdio>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <exception>
#include <stdexcept>

void doit( char* p ) {
    for ( int j=0; j<20; ++j ) {
        fprintf( stderr, "%d %d\n", j, int(p[j]) );
    }
}

void trapped(int) {
    throw std::runtime_error("Memory violation");
}

int main() {
    signal( SIGSEGV, trapped );
    int pgsize = getpagesize();
    fprintf( stderr, "Page size: %d\n", pgsize );
    uint8_t* ptr = (uint8_t*)mmap( NULL, 2*pgsize, PROT_READ|PROT_WRITE, 
    MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 );
    if ( ptr == MAP_FAILED ) {
        fprintf(stderr, "Memory map failed: %s\n", strerror(errno) );
        return 1;
    }
    int res = mprotect(ptr+pgsize,pgsize,PROT_NONE);
    if ( res!=0 ) {
        fprintf(stderr, "Failed to protect memory\n");
        return 2;
    }

    char* s = (char*)(ptr + pgsize - 10);

    try {
        doit( s );
    }
    catch( std::exception& ex ) {
        fprintf( stderr, "Caught exception:%s\n", ex.what());
    }
}

Godbolt:https://godbolt.org/z/oaMoTnaPo

运行的结果是:

Page size: 4096
0 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
Caught exception:Memory violation

评论

1赞 nneonneo 1/14/2023
值得指出的是,这在使用的内存方面非常昂贵(特别是对于小分配 - 因为它总是占用 ~8K 的通常页面大小),但在 CPU 时间方面却不是。它也不能处理(公认更罕见的)下溢条件,例如。ptr[-1]
0赞 Peter 1/14/2023
同样值得指出的是,这种方法不是标准的 C++ - 它特定于一个操作系统(或操作系统系列)。
0赞 Henrique Bucher 1/14/2023
@Peter 真的。C++ 标准在功能方面非常差。