Ore*_*lom 4 c gcc address-sanitizer
我正在学习地址消毒剂:
#include <stdio.h>
int main(int argc, char **argv)
{
int array[30]={0};
(void) printf("%d\n", array[179]); // <--- should crash, right?
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但我无法触发任何错误/警告:
#include <stdio.h>
int main(int argc, char **argv)
{
int array[30]={0};
(void) printf("%d\n", array[179]); // <--- should crash, right?
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在 的情况下-fsanitize=address
,使用有限大小的影子内存来检查内存访问,其中堆栈缓冲区被两个红区包围(一个在缓冲区之前,一个在缓冲区之后)。如果访问发生在红区内,Asan 会检测到错误并中止执行。然而,这些红区非常小,因为它们旨在检测缓冲区溢出/溢出错误,而不是使用大索引进行疯狂的越界访问。
所以你的情况是这样的:
Shadow bytes: 00 f1 f1 f1 f1 00 00 00 00 00 f3 f3 f3 f3 00 00 ... [00]
| redzone | array | redzone | ^^
read happens here
Addressable: 00
Stack left redzone: f1
Stack right redzone: f3
Run Code Online (Sandbox Code Playgroud)
并且有缺陷的内存读取未被检测到。
您想要检测此类错误的是-fsanitize=undefined
,或者更具体地说,是 或-fsanitize=bounds
之一-fsanitize=bounds-strict
。在这种情况下,进行边界检查时会考虑数组的定义及其类型,并且每次访问时都会通过其标识符检查边界。
$ gcc -fsanitize=undefined main.c -o main
$ ./main
main.c:5:20: runtime error: index 179 out of bounds for type 'int [30]'
main.c:5:20: runtime error: load of address 0xfffffffff68c with insufficient space for an object of type 'int'
0xfffffffff68c: note: pointer points here
87 08 00 00 00 00 00 00 06 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 11 00 00 00 00 00 00 00
^
0
Run Code Online (Sandbox Code Playgroud)
但请注意,这通常不会让您免于执行以下操作:
static void foo(int *arr) {
printf("%d\n", arr[179]);
}
int main(void) {
int array[30] = {0};
foo(array);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
arr
因为在这种情况下,函数内部无法知道的边界foo
。
或者,您也可以考虑手动毒害影子内存:
#include <stdio.h>
#include <sanitizer/asan_interface.h>
int main(void) {
int array[30] = {0};
// Poison 200 * sizeof(int) bytes after the end of array
ASAN_POISON_MEMORY_REGION(arr + 30, 200 * sizeof(int));
printf("%d\n", arr[179]); // Now this will get detected
return 0;
}
Run Code Online (Sandbox Code Playgroud)
然而,这也有其局限性,因为您应该避免污染堆栈上的其他缓冲区/变量。在上面的简单示例中,进行如此大的手动中毒可能是可以的,但一般情况下不行。