2013-06-07 17:38:55 +08:00
|
|
|
// RUN: %clangxx_asan -O1 %s -o %t
|
2013-08-07 17:14:30 +08:00
|
|
|
// RUN: not %t 0 2>&1 | FileCheck %s --check-prefix=CHECK0
|
|
|
|
// RUN: not %t 1 2>&1 | FileCheck %s --check-prefix=CHECK1
|
|
|
|
// RUN: not %t 2 2>&1 | FileCheck %s --check-prefix=CHECK2
|
|
|
|
// RUN: not %t 3 2>&1 | FileCheck %s --check-prefix=CHECK3
|
[asan] Change the way we report the alloca frame on stack-buff-overflow.
Before: the function name was stored by the compiler as a constant string
and the run-time was printing it.
Now: the PC is stored instead and the run-time prints the full symbolized frame.
This adds a couple of instructions into every function with non-empty stack frame,
but also reduces the binary size because we store less strings (I saw 2% size reduction).
This change bumps the asan ABI version to v3.
compiler-rt part, llvm part will follow.
Example of report (now):
==31711==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffa77cf1c5 at pc 0x41feb0 bp 0x7fffa77cefb0 sp 0x7fffa77cefa8
READ of size 1 at 0x7fffa77cf1c5 thread T0
#0 0x41feaf in Frame0(int, char*, char*, char*) stack-oob-frames.cc:20
#1 0x41f7ff in Frame1(int, char*, char*) stack-oob-frames.cc:24
#2 0x41f477 in Frame2(int, char*) stack-oob-frames.cc:28
#3 0x41f194 in Frame3(int) stack-oob-frames.cc:32
#4 0x41eee0 in main stack-oob-frames.cc:38
#5 0x7f0c5566f76c (/lib/x86_64-linux-gnu/libc.so.6+0x2176c)
#6 0x41eb1c (/usr/local/google/kcc/llvm_cmake/a.out+0x41eb1c)
Address 0x7fffa77cf1c5 is located in stack of thread T0 at offset 293 in frame
#0 0x41f87f in Frame0(int, char*, char*, char*) stack-oob-frames.cc:12 <<<<<<<<<<<<<< this is new
This frame has 6 object(s):
[32, 36) 'frame.addr'
[96, 104) 'a.addr'
[160, 168) 'b.addr'
[224, 232) 'c.addr'
[288, 292) 's'
[352, 360) 'd'
llvm-svn: 177723
2013-03-22 18:36:24 +08:00
|
|
|
|
|
|
|
#define NOINLINE __attribute__((noinline))
|
|
|
|
inline void break_optimization(void *arg) {
|
|
|
|
__asm__ __volatile__("" : : "r" (arg) : "memory");
|
|
|
|
}
|
|
|
|
|
|
|
|
NOINLINE static void Frame0(int frame, char *a, char *b, char *c) {
|
|
|
|
char s[4] = {0};
|
|
|
|
char *d = s;
|
|
|
|
break_optimization(&d);
|
|
|
|
switch (frame) {
|
|
|
|
case 3: a[5]++; break;
|
|
|
|
case 2: b[5]++; break;
|
|
|
|
case 1: c[5]++; break;
|
|
|
|
case 0: d[5]++; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NOINLINE static void Frame1(int frame, char *a, char *b) {
|
|
|
|
char c[4] = {0}; Frame0(frame, a, b, c);
|
|
|
|
break_optimization(0);
|
|
|
|
}
|
|
|
|
NOINLINE static void Frame2(int frame, char *a) {
|
|
|
|
char b[4] = {0}; Frame1(frame, a, b);
|
|
|
|
break_optimization(0);
|
|
|
|
}
|
|
|
|
NOINLINE static void Frame3(int frame) {
|
|
|
|
char a[4] = {0}; Frame2(frame, a);
|
|
|
|
break_optimization(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
if (argc != 2) return 1;
|
|
|
|
Frame3(argv[1][0] - '0');
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK0: AddressSanitizer: stack-buffer-overflow
|
|
|
|
// CHECK0: #0{{.*}}Frame0
|
|
|
|
// CHECK0: #1{{.*}}Frame1
|
|
|
|
// CHECK0: #2{{.*}}Frame2
|
|
|
|
// CHECK0: #3{{.*}}Frame3
|
|
|
|
// CHECK0: is located in stack of thread T0 at offset
|
|
|
|
// CHECK0-NEXT: #0{{.*}}Frame0
|
|
|
|
//
|
|
|
|
// CHECK1: AddressSanitizer: stack-buffer-overflow
|
|
|
|
// CHECK1: is located in stack of thread T0 at offset
|
|
|
|
// CHECK1-NEXT: #0{{.*}}Frame1
|
|
|
|
//
|
|
|
|
// CHECK2: AddressSanitizer: stack-buffer-overflow
|
|
|
|
// CHECK2: is located in stack of thread T0 at offset
|
|
|
|
// CHECK2-NEXT: #0{{.*}}Frame2
|
|
|
|
//
|
|
|
|
// CHECK3: AddressSanitizer: stack-buffer-overflow
|
|
|
|
// CHECK3: is located in stack of thread T0 at offset
|
|
|
|
// CHECK3-NEXT: #0{{.*}}Frame3
|