| 1 | // Test that out-of-scope local variables are ignored by LSan. |
| 2 | |
| 3 | // LSan-in-ASan fails at -O0 on aarch64, because the stack use-after-return |
| 4 | // instrumentation stashes the argument to `PutPointerOnStaleStack` on the stack |
| 5 | // in order to conditionally call __asan_stack_malloc. This subverts our |
| 6 | // expectations for this test, where we assume the pointer is never stashed |
| 7 | // except at the bottom of the dead frame. Building at -O1 or greater solves |
| 8 | // this problem, because the compiler is smart enough to stash the argument in a |
| 9 | // callee-saved register for rematerialization instead. |
| 10 | // RUN: %clangxx_lsan -O1 %s -o %t |
| 11 | |
| 12 | // RUN: %env_lsan_opts="report_objects=1:use_registers=0:use_stacks=1" not %run %t 2>&1 | FileCheck %s |
| 13 | // RUN: %env_lsan_opts="report_objects=1:use_registers=0:use_stacks=1:exitcode=0" %run %t 2>&1 | FileCheck --check-prefix=CHECK-sanity %s |
| 14 | // |
| 15 | // x86 passes parameters through stack that may lead to false negatives |
| 16 | // The same applies to s390x register save areas. |
| 17 | // UNSUPPORTED: i686,target={{(x86|powerpc64|arm|s390x).*}} |
| 18 | |
| 19 | #include <stdio.h> |
| 20 | #include <stdlib.h> |
| 21 | #include "sanitizer_common/print_address.h" |
| 22 | |
| 23 | void **pp; |
| 24 | |
| 25 | // Put pointer far enough on the stack that LSan has space to run in without |
| 26 | // overwriting it. |
| 27 | // Hopefully the argument p will be passed on a register, saving us from false |
| 28 | // negatives. |
| 29 | __attribute__((noinline)) |
| 30 | void *PutPointerOnStaleStack(void *p) { |
| 31 | void *locals[2048]; |
| 32 | locals[0] = p; |
| 33 | pp = &locals[0]; |
| 34 | print_address("Test alloc: " , 1, locals[0]); |
| 35 | return 0; |
| 36 | } |
| 37 | |
| 38 | int main() { |
| 39 | PutPointerOnStaleStack(p: malloc(size: 1337)); |
| 40 | return 0; |
| 41 | } |
| 42 | |
| 43 | // This must run after LSan, to ensure LSan didn't overwrite the pointer before |
| 44 | // it had a chance to see it. If LSan is invoked with atexit(), this works. |
| 45 | // Otherwise, we need a different method. |
| 46 | __attribute__((destructor)) |
| 47 | __attribute__((no_sanitize_address)) |
| 48 | __attribute__((no_sanitize("hwaddress" ))) |
| 49 | void ConfirmPointerHasSurvived() { |
| 50 | print_address("Value after LSan: " , 1, *pp); |
| 51 | } |
| 52 | // CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] |
| 53 | // CHECK-sanity: Test alloc: [[ADDR:0x[0-9,a-f]+]] |
| 54 | // CHECK: LeakSanitizer: detected memory leaks |
| 55 | // CHECK: [[ADDR]] (1337 bytes) |
| 56 | // CHECK: SUMMARY: {{.*}}Sanitizer: |
| 57 | // CHECK-sanity: Value after LSan: [[ADDR]] |
| 58 | |