提问人:MIA 提问时间:1/14/2023 最后编辑:MIA 更新时间:1/14/2023 访问量:111
如何检测无效读取(使用代码而不是 valgrind)
How to detect invalid reads (using code not valgrind)
问:
假设你像这样分配了一个指向 char 的指针
char *ptr = malloc(10 * sizeof(char))
如果这个 ptr 被传递给另一个函数而没有传递它的大小,我们是否可以检测到 ptr[10] 正在读取不属于这个指针的内存。
我知道如果我使用 valgrind,我会得到无效读取,但我想编写一个代码以在发生这种情况时抛出异常。
答:
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++ 标准在功能方面非常差。
评论
std::array<char, 10>
std::vector<char>
malloc()
free()
malloc
new[]
delete[]
malloc
free