forked from OSchip/llvm-project
[hwasan] Detect use after scope within function.
Reviewed By: vitalybuka Differential Revision: https://reviews.llvm.org/D105201
This commit is contained in:
parent
7397dcb403
commit
66b4aafa2e
|
@ -0,0 +1,68 @@
|
|||
// Tests use-after-scope detection and reporting.
|
||||
// RUN: %clang_hwasan -mllvm -hwasan-use-after-scope -g %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %clang_hwasan -mllvm -hwasan-use-after-scope -g %s -o %t && not %env_hwasan_opts=symbolize=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOSYM
|
||||
|
||||
// RUN: %clang_hwasan -mllvm -hwasan-use-after-scope=false -g %s -o %t && %run %t 2>&1
|
||||
// Use after scope is turned off by default.
|
||||
// RUN: %clang_hwasan -g %s -o %t && %run %t 2>&1
|
||||
|
||||
// RUN: %clang_hwasan -fexperimental-new-pass-manager -mllvm -hwasan-use-after-scope -g %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %clang_hwasan -fno-experimental-new-pass-manager -mllvm -hwasan-use-after-scope -g %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
// Stack histories currently are not recorded on x86.
|
||||
// XFAIL: x86_64
|
||||
|
||||
void USE(void *x) { // pretend_to_do_something(void *x)
|
||||
__asm__ __volatile__(""
|
||||
:
|
||||
: "r"(x)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
__attribute__((noinline)) void Unrelated1() {
|
||||
int A[2];
|
||||
USE(&A[0]);
|
||||
}
|
||||
__attribute__((noinline)) void Unrelated2() {
|
||||
int BB[3];
|
||||
USE(&BB[0]);
|
||||
}
|
||||
__attribute__((noinline)) void Unrelated3() {
|
||||
int CCC[4];
|
||||
USE(&CCC[0]);
|
||||
}
|
||||
|
||||
__attribute__((noinline)) char buggy() {
|
||||
char *volatile p;
|
||||
{
|
||||
char zzz[0x1000];
|
||||
p = zzz;
|
||||
}
|
||||
return *p;
|
||||
}
|
||||
|
||||
int main() {
|
||||
Unrelated1();
|
||||
Unrelated2();
|
||||
Unrelated3();
|
||||
char p = buggy();
|
||||
return p;
|
||||
// CHECK: READ of size 1 at
|
||||
// CHECK: #0 {{.*}} in buggy{{.*}}stack-uas.c:[[@LINE-10]]
|
||||
// CHECK: Cause: stack tag-mismatch
|
||||
// CHECK: is located in stack of thread
|
||||
// CHECK: Potentially referenced stack objects:
|
||||
// CHECK-NEXT: zzz in buggy {{.*}}stack-uas.c:[[@LINE-17]]
|
||||
// CHECK-NEXT: Memory tags around the buggy address
|
||||
|
||||
// NOSYM: Previously allocated frames:
|
||||
// NOSYM-NEXT: record_addr:0x{{.*}} record:0x{{.*}} ({{.*}}/stack-uas.c.tmp+0x{{.*}}){{$}}
|
||||
// NOSYM-NEXT: record_addr:0x{{.*}} record:0x{{.*}} ({{.*}}/stack-uas.c.tmp+0x{{.*}}){{$}}
|
||||
// NOSYM-NEXT: record_addr:0x{{.*}} record:0x{{.*}} ({{.*}}/stack-uas.c.tmp+0x{{.*}}){{$}}
|
||||
// NOSYM-NEXT: record_addr:0x{{.*}} record:0x{{.*}} ({{.*}}/stack-uas.c.tmp+0x{{.*}}){{$}}
|
||||
// NOSYM-NEXT: Memory tags around the buggy address
|
||||
|
||||
// CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in buggy
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
// RUN: %clangxx_asan %stdcxx11 -O1 -fsanitize-address-use-after-scope %s -o %t && \
|
||||
// RUN: not %run %t 2>&1 | FileCheck %s
|
||||
//
|
||||
// Not expected to work yet with HWAsan
|
||||
// XFAIL: *
|
||||
// This is the ASAN test of the same name ported to HWAsan.
|
||||
|
||||
// RUN: %clangxx_hwasan -mllvm -hwasan-use-after-scope --std=c++11 -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
// REQUIRES: aarch64-target-arch
|
||||
|
||||
#include <functional>
|
||||
|
||||
|
@ -12,8 +12,9 @@ int main() {
|
|||
int x = 0;
|
||||
f = [&x]() __attribute__((noinline)) {
|
||||
return x; // BOOM
|
||||
// CHECK: ERROR: AddressSanitizer: stack-use-after-scope
|
||||
// CHECK: ERROR: HWAddressSanitizer: tag-mismatch
|
||||
// CHECK: #0 0x{{.*}} in {{.*}}use-after-scope-capture.cpp:[[@LINE-2]]
|
||||
// CHECK: Cause: stack tag-mismatch
|
||||
};
|
||||
}
|
||||
return f(); // BOOM
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \
|
||||
// This is the ASAN test of the same name ported to HWAsan.
|
||||
|
||||
// RUN: %clangxx_hwasan -mllvm -hwasan-use-after-scope -O1 %s -o %t && \
|
||||
// RUN: not %run %t 2>&1 | FileCheck %s
|
||||
//
|
||||
// Not expected to work yet with HWAsan.
|
||||
// XFAIL: *
|
||||
|
||||
// REQUIRES: aarch64-target-arch
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -10,7 +12,7 @@ struct IntHolder {
|
|||
explicit IntHolder(int *val = 0) : val_(val) {}
|
||||
__attribute__((noinline)) ~IntHolder() {
|
||||
printf("Value: %d\n", *val_); // BOOM
|
||||
// CHECK: ERROR: AddressSanitizer: stack-use-after-scope
|
||||
// CHECK: ERROR: HWAddressSanitizer: tag-mismatch
|
||||
// CHECK: #0 0x{{.*}} in IntHolder::~IntHolder{{.*}}.cpp:[[@LINE-2]]
|
||||
}
|
||||
void set(int *val) { val_ = val; }
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
// RUN: %clangxx_asan -O0 -fsanitize-address-use-after-scope %s -o %t && %run %t
|
||||
// This is the ASAN test of the same name ported to HWAsan.
|
||||
|
||||
// RUN: %clangxx_hwasan -mllvm -hwasan-use-after-scope -O0 %s -o %t && %run %t
|
||||
|
||||
// Function jumps over variable initialization making lifetime analysis
|
||||
// ambiguous. Asan should ignore such variable and program must not fail.
|
||||
//
|
||||
// Not expected to work yet with HWAsan.
|
||||
// XFAIL: *
|
||||
|
||||
// REQUIRES: aarch64-target-arch
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \
|
||||
// This is the ASAN test of the same name ported to HWAsan.
|
||||
|
||||
// RUN: %clangxx_hwasan -mllvm -hwasan-use-after-scope -O1 %s -o %t && \
|
||||
// RUN: not %run %t 2>&1 | FileCheck %s
|
||||
//
|
||||
// Not expected to work yet with HWAsan.
|
||||
// XFAIL: *
|
||||
|
||||
// REQUIRES: aarch64-target-arch
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
int *p;
|
||||
bool b = true;
|
||||
|
@ -13,6 +15,7 @@ int main() {
|
|||
p = x + 1;
|
||||
}
|
||||
return *p; // BOOM
|
||||
// CHECK: ERROR: AddressSanitizer: stack-use-after-scope
|
||||
// CHECK: ERROR: HWAddressSanitizer: tag-mismatch
|
||||
// CHECK: #0 0x{{.*}} in main {{.*}}.cpp:[[@LINE-2]]
|
||||
// CHECK: Cause: stack tag-mismatch
|
||||
}
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
// This is the ASAN test of the same name ported to HWAsan.
|
||||
|
||||
// Test with "-O2" only to make sure inlining (leading to use-after-scope)
|
||||
// happens. "always_inline" is not enough, as Clang doesn't emit
|
||||
// llvm.lifetime intrinsics at -O0.
|
||||
//
|
||||
// RUN: %clangxx_asan -O2 -fsanitize-address-use-after-scope %s -o %t && \
|
||||
// RUN: %clangxx_hwasan -mllvm -hwasan-use-after-scope -O2 %s -o %t && \
|
||||
// RUN: not %run %t 2>&1 | FileCheck %s
|
||||
//
|
||||
// Not expected to work yet with HWAsan.
|
||||
// XFAIL: *
|
||||
|
||||
// REQUIRES: aarch64-target-arch
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
int *arr;
|
||||
|
||||
__attribute__((always_inline)) void inlined(int arg) {
|
||||
int x[5];
|
||||
for (int i = 0; i < arg; i++)
|
||||
|
@ -20,12 +21,6 @@ __attribute__((always_inline)) void inlined(int arg) {
|
|||
int main(int argc, char *argv[]) {
|
||||
inlined(argc);
|
||||
return arr[argc - 1]; // BOOM
|
||||
// CHECK: ERROR: AddressSanitizer: stack-use-after-scope
|
||||
// CHECK: READ of size 4 at 0x{{.*}} thread T0
|
||||
// CHECK: #0 0x{{.*}} in main
|
||||
// CHECK: {{.*}}use-after-scope-inlined.cpp:[[@LINE-4]]
|
||||
// CHECK: Address 0x{{.*}} is located in stack of thread T0 at offset [[OFFSET:[^ ]*]] in frame
|
||||
// CHECK: {{.*}} in main
|
||||
// CHECK: This frame has
|
||||
// CHECK: {{\[}}[[OFFSET]], {{.*}}) 'x.i' (line [[@LINE-15]])
|
||||
// CHECK: ERROR: HWAddressSanitizer: tag-mismatch
|
||||
// CHECK: Cause: stack tag-mismatch
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \
|
||||
// This is the ASAN test of the same name ported to HWAsan.
|
||||
|
||||
// RUN: %clangxx_hwasan -mllvm -hwasan-use-after-scope -O1 %s -o %t && \
|
||||
// RUN: not %run %t 2>&1 | FileCheck %s
|
||||
//
|
||||
// Not expected to work yet with HWAsan.
|
||||
// XFAIL: *
|
||||
|
||||
// REQUIRES: aarch64-target-arch
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
volatile int *p;
|
||||
|
||||
|
@ -13,8 +15,7 @@ int main() {
|
|||
p = x + i;
|
||||
}
|
||||
return *p; // BOOM
|
||||
// CHECK: ERROR: AddressSanitizer: stack-use-after-scope
|
||||
// CHECK: ERROR: HWAddressSanitizer: tag-mismatch
|
||||
// CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope-loop-bug.cpp:[[@LINE-2]]
|
||||
// CHECK: Address 0x{{.*}} is located in stack of thread T{{.*}} at offset [[OFFSET:[^ ]+]] in frame
|
||||
// {{\[}}[[OFFSET]], {{[0-9]+}}) 'x'
|
||||
// CHECK: Cause: stack tag-mismatch
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \
|
||||
// This is the ASAN test of the same name ported to HWAsan.
|
||||
|
||||
// RUN: %clangxx_hwasan -mllvm -hwasan-use-after-scope -O1 %s -o %t && \
|
||||
// RUN: not %run %t 2>&1 | FileCheck %s
|
||||
//
|
||||
// Not expected to work yet with HWAsan.
|
||||
// XFAIL: *
|
||||
|
||||
// REQUIRES: aarch64-target-arch
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -14,8 +16,7 @@ int main() {
|
|||
p = &x;
|
||||
}
|
||||
return *p; // BOOM
|
||||
// CHECK: ERROR: AddressSanitizer: stack-use-after-scope
|
||||
// CHECK: ERROR: HWAddressSanitizer: tag-mismatch
|
||||
// CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope-loop-removed.cpp:[[@LINE-2]]
|
||||
// CHECK: Address 0x{{.*}} is located in stack of thread T{{.*}} at offset [[OFFSET:[^ ]+]] in frame
|
||||
// {{\[}}[[OFFSET]], {{[0-9]+}}) 'x'
|
||||
// CHECK: Cause: stack tag-mismatch
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \
|
||||
// This is the ASAN test of the same name ported to HWAsan.
|
||||
|
||||
// RUN: %clangxx_hwasan -mllvm -hwasan-use-after-scope -O1 %s -o %t && \
|
||||
// RUN: not %run %t 2>&1 | FileCheck %s
|
||||
//
|
||||
// Not expected to work yet with HWAsan.
|
||||
// XFAIL: *
|
||||
|
||||
// REQUIRES: aarch64-target-arch
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
int *p[3];
|
||||
|
||||
|
@ -12,6 +14,7 @@ int main() {
|
|||
p[i] = &x;
|
||||
}
|
||||
return **p; // BOOM
|
||||
// CHECK: ERROR: AddressSanitizer: stack-use-after-scope
|
||||
// CHECK: ERROR: HWAddressSanitizer: tag-mismatch
|
||||
// CHECK: #0 0x{{.*}} in main {{.*}}.cpp:[[@LINE-2]]
|
||||
// CHECK: Cause: stack tag-mismatch
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && %run %t
|
||||
//
|
||||
// Not expected to work yet with HWAsan.
|
||||
// XFAIL: *
|
||||
// This is the ASAN test of the same name ported to HWAsan.
|
||||
|
||||
// RUN: %clangxx_hwasan -mllvm -hwasan-use-after-scope -O1 %s -o %t && %run %t
|
||||
|
||||
// REQUIRES: aarch64-target-arch
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// RUN: %clangxx_asan %stdcxx11 -O1 -fsanitize-address-use-after-scope %s -o %t && \
|
||||
// This is the ASAN test of the same name ported to HWAsan.
|
||||
|
||||
// RUN: %clangxx_hwasan -mllvm -hwasan-use-after-scope -std=c++11 -O1 %s -o %t && \
|
||||
// RUN: not %run %t 2>&1 | FileCheck %s
|
||||
//
|
||||
// Not expected to work yet with HWAsan.
|
||||
// XFAIL: *
|
||||
|
||||
// REQUIRES: aarch64-target-arch
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
struct IntHolder {
|
||||
int val;
|
||||
|
@ -17,7 +19,8 @@ __attribute__((noinline)) void save(const IntHolder &holder) {
|
|||
int main(int argc, char *argv[]) {
|
||||
save({argc});
|
||||
int x = saved->val; // BOOM
|
||||
// CHECK: ERROR: AddressSanitizer: stack-use-after-scope
|
||||
// CHECK: ERROR: HWAddressSanitizer: tag-mismatch
|
||||
// CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope-temp.cpp:[[@LINE-2]]
|
||||
// CHECK: Cause: stack tag-mismatch
|
||||
return x;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// RUN: %clangxx_asan %stdcxx11 -O1 -fsanitize-address-use-after-scope %s -o %t && \
|
||||
// This is the ASAN test of the same name ported to HWAsan.
|
||||
|
||||
// RUN: %clangxx_hwasan -mllvm -hwasan-use-after-scope -std=c++11 -O1 %s -o %t && \
|
||||
// RUN: not %run %t 2>&1 | FileCheck %s
|
||||
//
|
||||
// Not expected to work yet with HWAsan.
|
||||
// XFAIL: *
|
||||
|
||||
// REQUIRES: aarch64-target-arch
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
struct IntHolder {
|
||||
__attribute__((noinline)) const IntHolder &Self() const {
|
||||
|
@ -16,7 +18,8 @@ const IntHolder *saved;
|
|||
int main(int argc, char *argv[]) {
|
||||
saved = &IntHolder().Self();
|
||||
int x = saved->val; // BOOM
|
||||
// CHECK: ERROR: AddressSanitizer: stack-use-after-scope
|
||||
// CHECK: ERROR: HWAddressSanitizer: tag-mismatch
|
||||
// CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope-temp2.cpp:[[@LINE-2]]
|
||||
// CHECK: Cause: stack tag-mismatch
|
||||
return x;
|
||||
}
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
// RUN: %clangxx_asan %stdcxx11 -O0 -fsanitize-address-use-after-scope %s -o %t
|
||||
// This is the ASAN test of the same name ported to HWAsan.
|
||||
|
||||
// RUN: %clangxx_hwasan -mllvm -hwasan-use-after-scope -std=c++11 -O0 %s -o %t
|
||||
// RUN: not %run %t 0 2>&1 | FileCheck %s
|
||||
// RUN: not %run %t 1 2>&1 | FileCheck %s
|
||||
// RUN: not %run %t 2 2>&1 | FileCheck %s
|
||||
// RUN: not %run %t 3 2>&1 | FileCheck %s
|
||||
// RUN: not %run %t 4 2>&1 | FileCheck %s
|
||||
// RUN: not %run %t 5 2>&1 | FileCheck %s
|
||||
// RUN: not %run %t 6 2>&1 | FileCheck %s
|
||||
// The std::vector case is broken because of limited lifetime tracking.
|
||||
// TODO(fmayer): Fix and enable.
|
||||
// RUN: not %run %t 7 2>&1 | FileCheck %s
|
||||
// RUN: not %run %t 8 2>&1 | FileCheck %s
|
||||
// RUN: not %run %t 9 2>&1 | FileCheck %s
|
||||
// RUN: not %run %t 10 2>&1 | FileCheck %s
|
||||
//
|
||||
// Not expected to work yet with HWAsan.
|
||||
// XFAIL: *
|
||||
|
||||
// REQUIRES: aarch64-target-arch
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
|
@ -46,10 +49,9 @@ __attribute__((noinline)) void test() {
|
|||
}
|
||||
|
||||
ptr.Access();
|
||||
// CHECK: ERROR: AddressSanitizer: stack-use-after-scope
|
||||
// CHECK: ERROR: HWAddressSanitizer: tag-mismatch
|
||||
// CHECK: #{{[0-9]+}} 0x{{.*}} in {{(void )?test.*\((void)?\) .*}}use-after-scope-types.cpp
|
||||
// CHECK: Address 0x{{.*}} is located in stack of thread T{{.*}} at offset [[OFFSET:[^ ]+]] in frame
|
||||
// {{\[}}[[OFFSET]], {{[0-9]+}}) 'x'
|
||||
// CHECK: Cause: stack tag-mismatch
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \
|
||||
// This is the ASAN test of the same name ported to HWAsan.
|
||||
|
||||
// RUN: %clangxx_hwasan -mllvm -hwasan-use-after-scope -O1 %s -o %t && \
|
||||
// RUN: not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
// -fsanitize-address-use-after-scope is now on by default:
|
||||
// RUN: %clangxx_asan -O1 %s -o %t && \
|
||||
// RUN: not %run %t 2>&1 | FileCheck %s
|
||||
//
|
||||
// Not expected to work yet with HWAsan.
|
||||
// XFAIL: *
|
||||
// REQUIRES: aarch64-target-arch
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
volatile int *p = 0;
|
||||
|
||||
|
@ -16,9 +14,8 @@ int main() {
|
|||
p = &x;
|
||||
}
|
||||
*p = 5; // BOOM
|
||||
// CHECK: ERROR: AddressSanitizer: stack-use-after-scope
|
||||
// CHECK: ERROR: HWAddressSanitizer: tag-mismatch
|
||||
// CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope.cpp:[[@LINE-2]]
|
||||
// CHECK: Address 0x{{.*}} is located in stack of thread T{{.*}} at offset [[OFFSET:[^ ]+]] in frame
|
||||
// {{\[}}[[OFFSET]], {{[0-9]+}}) 'x'
|
||||
// CHECK: Cause: stack tag-mismatch
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Analysis/PostDominators.h"
|
||||
#include "llvm/Analysis/StackSafetyAnalysis.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/BinaryFormat/ELF.h"
|
||||
#include "llvm/IR/Attributes.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
|
@ -26,6 +28,7 @@
|
|||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/DebugInfoMetadata.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/InlineAsm.h"
|
||||
|
@ -41,6 +44,7 @@
|
|||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/InitializePasses.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/PassRegistry.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
|
@ -115,6 +119,11 @@ static cl::opt<bool>
|
|||
cl::Hidden, cl::desc("Use Stack Safety analysis results"),
|
||||
cl::Optional);
|
||||
|
||||
static cl::opt<bool>
|
||||
ClUseAfterScope("hwasan-use-after-scope",
|
||||
cl::desc("detect use after scope within function"),
|
||||
cl::Hidden, cl::init(false));
|
||||
|
||||
static cl::opt<bool> ClUARRetagToZero(
|
||||
"hwasan-uar-retag-to-zero",
|
||||
cl::desc("Clear alloca tags before returning from the function to allow "
|
||||
|
@ -220,9 +229,21 @@ bool shouldUseStackSafetyAnalysis(const Triple &TargetTriple,
|
|||
return shouldInstrumentStack(TargetTriple) &&
|
||||
mightUseStackSafetyAnalysis(DisableOptimization);
|
||||
}
|
||||
|
||||
bool shouldDetectUseAfterScope(const Triple &TargetTriple) {
|
||||
return ClUseAfterScope && shouldInstrumentStack(TargetTriple);
|
||||
}
|
||||
|
||||
/// An instrumentation pass implementing detection of addressability bugs
|
||||
/// using tagged pointers.
|
||||
class HWAddressSanitizer {
|
||||
private:
|
||||
struct AllocaInfo {
|
||||
AllocaInst *AI;
|
||||
SmallVector<IntrinsicInst *, 2> LifetimeStart;
|
||||
SmallVector<IntrinsicInst *, 2> LifetimeEnd;
|
||||
};
|
||||
|
||||
public:
|
||||
HWAddressSanitizer(Module &M, bool CompileKernel, bool Recover,
|
||||
const StackSafetyGlobalInfo *SSI)
|
||||
|
@ -237,7 +258,9 @@ public:
|
|||
|
||||
void setSSI(const StackSafetyGlobalInfo *S) { SSI = S; }
|
||||
|
||||
bool sanitizeFunction(Function &F);
|
||||
bool sanitizeFunction(Function &F,
|
||||
llvm::function_ref<const DominatorTree &()> GetDT,
|
||||
llvm::function_ref<const PostDominatorTree &()> GetPDT);
|
||||
void initializeModule();
|
||||
void createHwasanCtorComdat();
|
||||
|
||||
|
@ -260,13 +283,16 @@ public:
|
|||
Instruction *I, SmallVectorImpl<InterestingMemoryOperand> &Interesting);
|
||||
|
||||
bool isInterestingAlloca(const AllocaInst &AI);
|
||||
bool tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag, size_t Size);
|
||||
void tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag, size_t Size);
|
||||
Value *tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong, Value *Tag);
|
||||
Value *untagPointer(IRBuilder<> &IRB, Value *PtrLong);
|
||||
bool instrumentStack(
|
||||
SmallVectorImpl<AllocaInst *> &Allocas,
|
||||
MapVector<AllocaInst *, AllocaInfo> &AllocasToInstrument,
|
||||
SmallVector<Instruction *, 4> &UnrecognizedLifetimes,
|
||||
DenseMap<AllocaInst *, std::vector<DbgVariableIntrinsic *>> &AllocaDbgMap,
|
||||
SmallVectorImpl<Instruction *> &RetVec, Value *StackTag);
|
||||
SmallVectorImpl<Instruction *> &RetVec, Value *StackTag,
|
||||
llvm::function_ref<const DominatorTree &()> GetDT,
|
||||
llvm::function_ref<const PostDominatorTree &()> GetPDT);
|
||||
Value *readRegister(IRBuilder<> &IRB, StringRef Name);
|
||||
bool instrumentLandingPads(SmallVectorImpl<Instruction *> &RetVec);
|
||||
Value *getNextTagWithCall(IRBuilder<> &IRB);
|
||||
|
@ -315,6 +341,7 @@ private:
|
|||
void init(Triple &TargetTriple, bool InstrumentWithCalls);
|
||||
unsigned getObjectAlignment() const { return 1U << Scale; }
|
||||
};
|
||||
|
||||
ShadowMapping Mapping;
|
||||
|
||||
Type *VoidTy = Type::getVoidTy(M.getContext());
|
||||
|
@ -331,6 +358,7 @@ private:
|
|||
bool InstrumentLandingPads;
|
||||
bool InstrumentWithCalls;
|
||||
bool InstrumentStack;
|
||||
bool DetectUseAfterScope;
|
||||
bool UsePageAliases;
|
||||
|
||||
bool HasMatchAllTag = false;
|
||||
|
@ -377,14 +405,21 @@ public:
|
|||
}
|
||||
|
||||
bool runOnFunction(Function &F) override {
|
||||
if (shouldUseStackSafetyAnalysis(Triple(F.getParent()->getTargetTriple()),
|
||||
DisableOptimization)) {
|
||||
auto TargetTriple = Triple(F.getParent()->getTargetTriple());
|
||||
if (shouldUseStackSafetyAnalysis(TargetTriple, DisableOptimization)) {
|
||||
// We cannot call getAnalysis in doInitialization, that would cause a
|
||||
// crash as the required analyses are not initialized yet.
|
||||
HWASan->setSSI(
|
||||
&getAnalysis<StackSafetyGlobalInfoWrapperPass>().getResult());
|
||||
}
|
||||
return HWASan->sanitizeFunction(F);
|
||||
return HWASan->sanitizeFunction(
|
||||
F,
|
||||
[&]() -> const DominatorTree & {
|
||||
return getAnalysis<DominatorTreeWrapperPass>().getDomTree();
|
||||
},
|
||||
[&]() -> const PostDominatorTree & {
|
||||
return getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();
|
||||
});
|
||||
}
|
||||
|
||||
bool doFinalization(Module &M) override {
|
||||
|
@ -399,6 +434,8 @@ public:
|
|||
// This is so we don't need to plumb TargetTriple all the way to here.
|
||||
if (mightUseStackSafetyAnalysis(DisableOptimization))
|
||||
AU.addRequired<StackSafetyGlobalInfoWrapperPass>();
|
||||
AU.addRequired<DominatorTreeWrapperPass>();
|
||||
AU.addRequired<PostDominatorTreeWrapperPass>();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -417,6 +454,8 @@ INITIALIZE_PASS_BEGIN(
|
|||
"HWAddressSanitizer: detect memory bugs using tagged addressing.", false,
|
||||
false)
|
||||
INITIALIZE_PASS_DEPENDENCY(StackSafetyGlobalInfoWrapperPass)
|
||||
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
|
||||
INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
|
||||
INITIALIZE_PASS_END(
|
||||
HWAddressSanitizerLegacyPass, "hwasan",
|
||||
"HWAddressSanitizer: detect memory bugs using tagged addressing.", false,
|
||||
|
@ -438,13 +477,23 @@ HWAddressSanitizerPass::HWAddressSanitizerPass(bool CompileKernel, bool Recover,
|
|||
PreservedAnalyses HWAddressSanitizerPass::run(Module &M,
|
||||
ModuleAnalysisManager &MAM) {
|
||||
const StackSafetyGlobalInfo *SSI = nullptr;
|
||||
if (shouldUseStackSafetyAnalysis(llvm::Triple(M.getTargetTriple()),
|
||||
DisableOptimization))
|
||||
auto TargetTriple = llvm::Triple(M.getTargetTriple());
|
||||
if (shouldUseStackSafetyAnalysis(TargetTriple, DisableOptimization))
|
||||
SSI = &MAM.getResult<StackSafetyGlobalAnalysis>(M);
|
||||
|
||||
HWAddressSanitizer HWASan(M, CompileKernel, Recover, SSI);
|
||||
bool Modified = false;
|
||||
for (Function &F : M)
|
||||
Modified |= HWASan.sanitizeFunction(F);
|
||||
auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
|
||||
for (Function &F : M) {
|
||||
Modified |= HWASan.sanitizeFunction(
|
||||
F,
|
||||
[&]() -> const DominatorTree & {
|
||||
return FAM.getResult<DominatorTreeAnalysis>(F);
|
||||
},
|
||||
[&]() -> const PostDominatorTree & {
|
||||
return FAM.getResult<PostDominatorTreeAnalysis>(F);
|
||||
});
|
||||
}
|
||||
if (Modified)
|
||||
return PreservedAnalyses::none();
|
||||
return PreservedAnalyses::all();
|
||||
|
@ -566,6 +615,7 @@ void HWAddressSanitizer::initializeModule() {
|
|||
UsePageAliases = shouldUsePageAliases(TargetTriple);
|
||||
InstrumentWithCalls = shouldInstrumentWithCalls(TargetTriple);
|
||||
InstrumentStack = shouldInstrumentStack(TargetTriple);
|
||||
DetectUseAfterScope = shouldDetectUseAfterScope(TargetTriple);
|
||||
PointerTagShift = IsX86_64 ? 57 : 56;
|
||||
TagMaskByte = IsX86_64 ? 0x3F : 0xFF;
|
||||
|
||||
|
@ -968,7 +1018,7 @@ static uint64_t getAllocaSizeInBytes(const AllocaInst &AI) {
|
|||
return SizeInBytes * ArraySize;
|
||||
}
|
||||
|
||||
bool HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag,
|
||||
void HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag,
|
||||
size_t Size) {
|
||||
size_t AlignedSize = alignTo(Size, Mapping.getObjectAlignment());
|
||||
if (!UseShortGranules)
|
||||
|
@ -999,7 +1049,6 @@ bool HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag,
|
|||
AlignedSize - 1));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned HWAddressSanitizer::retagMask(unsigned AllocaNo) {
|
||||
|
@ -1232,16 +1281,23 @@ bool HWAddressSanitizer::instrumentLandingPads(
|
|||
}
|
||||
|
||||
bool HWAddressSanitizer::instrumentStack(
|
||||
SmallVectorImpl<AllocaInst *> &Allocas,
|
||||
MapVector<AllocaInst *, AllocaInfo> &AllocasToInstrument,
|
||||
SmallVector<Instruction *, 4> &UnrecognizedLifetimes,
|
||||
DenseMap<AllocaInst *, std::vector<DbgVariableIntrinsic *>> &AllocaDbgMap,
|
||||
SmallVectorImpl<Instruction *> &RetVec, Value *StackTag) {
|
||||
SmallVectorImpl<Instruction *> &RetVec, Value *StackTag,
|
||||
llvm::function_ref<const DominatorTree &()> GetDT,
|
||||
llvm::function_ref<const PostDominatorTree &()> GetPDT) {
|
||||
// Ideally, we want to calculate tagged stack base pointer, and rewrite all
|
||||
// alloca addresses using that. Unfortunately, offsets are not known yet
|
||||
// (unless we use ASan-style mega-alloca). Instead we keep the base tag in a
|
||||
// temp, shift-OR it into each alloca address and xor with the retag mask.
|
||||
// This generates one extra instruction per alloca use.
|
||||
for (unsigned N = 0; N < Allocas.size(); ++N) {
|
||||
auto *AI = Allocas[N];
|
||||
unsigned int I = 0;
|
||||
|
||||
for (auto &KV : AllocasToInstrument) {
|
||||
auto N = I++;
|
||||
auto *AI = KV.first;
|
||||
AllocaInfo &Info = KV.second;
|
||||
IRBuilder<> IRB(AI->getNextNode());
|
||||
|
||||
// Replace uses of the alloca with tagged address.
|
||||
|
@ -1268,17 +1324,39 @@ bool HWAddressSanitizer::instrumentStack(
|
|||
}
|
||||
|
||||
size_t Size = getAllocaSizeInBytes(*AI);
|
||||
size_t AlignedSize = alignTo(Size, Mapping.getObjectAlignment());
|
||||
bool StandardLifetime = UnrecognizedLifetimes.empty() &&
|
||||
Info.LifetimeStart.size() == 1 &&
|
||||
Info.LifetimeEnd.size() == 1;
|
||||
if (DetectUseAfterScope && StandardLifetime) {
|
||||
IntrinsicInst *Start = Info.LifetimeStart[0];
|
||||
IntrinsicInst *End = Info.LifetimeEnd[0];
|
||||
IRB.SetInsertPoint(Start->getNextNode());
|
||||
auto TagEnd = [&](Instruction *Node) {
|
||||
IRB.SetInsertPoint(Node);
|
||||
Value *UARTag = getUARTag(IRB, StackTag);
|
||||
tagAlloca(IRB, AI, UARTag, AlignedSize);
|
||||
};
|
||||
tagAlloca(IRB, AI, Tag, Size);
|
||||
|
||||
for (auto RI : RetVec) {
|
||||
if (!forAllReachableExits(GetDT(), GetPDT(), Start, End, RetVec, TagEnd))
|
||||
End->eraseFromParent();
|
||||
} else {
|
||||
tagAlloca(IRB, AI, Tag, Size);
|
||||
for (auto *RI : RetVec) {
|
||||
IRB.SetInsertPoint(RI);
|
||||
|
||||
// Re-tag alloca memory with the special UAR tag.
|
||||
Value *Tag = getUARTag(IRB, StackTag);
|
||||
tagAlloca(IRB, AI, Tag, alignTo(Size, Mapping.getObjectAlignment()));
|
||||
Value *UARTag = getUARTag(IRB, StackTag);
|
||||
tagAlloca(IRB, AI, UARTag, AlignedSize);
|
||||
}
|
||||
if (!StandardLifetime) {
|
||||
for (auto &II : Info.LifetimeStart)
|
||||
II->eraseFromParent();
|
||||
for (auto &II : Info.LifetimeEnd)
|
||||
II->eraseFromParent();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
for (auto &I : UnrecognizedLifetimes)
|
||||
I->eraseFromParent();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1300,7 +1378,9 @@ bool HWAddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
|
|||
!(SSI && SSI->isSafe(AI));
|
||||
}
|
||||
|
||||
bool HWAddressSanitizer::sanitizeFunction(Function &F) {
|
||||
bool HWAddressSanitizer::sanitizeFunction(
|
||||
Function &F, llvm::function_ref<const DominatorTree &()> GetDT,
|
||||
llvm::function_ref<const PostDominatorTree &()> GetPDT) {
|
||||
if (&F == HwasanCtorFunction)
|
||||
return false;
|
||||
|
||||
|
@ -1311,18 +1391,36 @@ bool HWAddressSanitizer::sanitizeFunction(Function &F) {
|
|||
|
||||
SmallVector<InterestingMemoryOperand, 16> OperandsToInstrument;
|
||||
SmallVector<MemIntrinsic *, 16> IntrinToInstrument;
|
||||
SmallVector<AllocaInst *, 8> AllocasToInstrument;
|
||||
MapVector<AllocaInst *, AllocaInfo> AllocasToInstrument;
|
||||
SmallVector<Instruction *, 8> RetVec;
|
||||
SmallVector<Instruction *, 8> LandingPadVec;
|
||||
SmallVector<Instruction *, 4> UnrecognizedLifetimes;
|
||||
DenseMap<AllocaInst *, std::vector<DbgVariableIntrinsic *>> AllocaDbgMap;
|
||||
for (auto &BB : F) {
|
||||
for (auto &Inst : BB) {
|
||||
if (InstrumentStack)
|
||||
if (InstrumentStack) {
|
||||
if (AllocaInst *AI = dyn_cast<AllocaInst>(&Inst)) {
|
||||
if (isInterestingAlloca(*AI))
|
||||
AllocasToInstrument.push_back(AI);
|
||||
AllocasToInstrument.insert({AI, {}});
|
||||
continue;
|
||||
}
|
||||
auto *II = dyn_cast<IntrinsicInst>(&Inst);
|
||||
if (II && (II->getIntrinsicID() == Intrinsic::lifetime_start ||
|
||||
II->getIntrinsicID() == Intrinsic::lifetime_end)) {
|
||||
AllocaInst *AI = findAllocaForValue(II->getArgOperand(1));
|
||||
if (!AI) {
|
||||
UnrecognizedLifetimes.push_back(&Inst);
|
||||
continue;
|
||||
}
|
||||
if (!isInterestingAlloca(*AI))
|
||||
continue;
|
||||
if (II->getIntrinsicID() == Intrinsic::lifetime_start)
|
||||
AllocasToInstrument[AI].LifetimeStart.push_back(II);
|
||||
else
|
||||
AllocasToInstrument[AI].LifetimeEnd.push_back(II);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst) ||
|
||||
isa<CleanupReturnInst>(Inst))
|
||||
|
@ -1377,13 +1475,15 @@ bool HWAddressSanitizer::sanitizeFunction(Function &F) {
|
|||
if (!AllocasToInstrument.empty()) {
|
||||
Value *StackTag =
|
||||
ClGenerateTagsWithCalls ? nullptr : getStackBaseTag(EntryIRB);
|
||||
instrumentStack(AllocasToInstrument, AllocaDbgMap, RetVec, StackTag);
|
||||
instrumentStack(AllocasToInstrument, UnrecognizedLifetimes, AllocaDbgMap,
|
||||
RetVec, StackTag, GetDT, GetPDT);
|
||||
}
|
||||
// Pad and align each of the allocas that we instrumented to stop small
|
||||
// uninteresting allocas from hiding in instrumented alloca's padding and so
|
||||
// that we have enough space to store real tags for short granules.
|
||||
DenseMap<AllocaInst *, AllocaInst *> AllocaToPaddedAllocaMap;
|
||||
for (AllocaInst *AI : AllocasToInstrument) {
|
||||
for (auto &KV : AllocasToInstrument) {
|
||||
AllocaInst *AI = KV.first;
|
||||
uint64_t Size = getAllocaSizeInBytes(*AI);
|
||||
uint64_t AlignedSize = alignTo(Size, Mapping.getObjectAlignment());
|
||||
AI->setAlignment(
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt -hwasan -hwasan-use-after-scope=1 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=SCOPE
|
||||
; RUN: opt -hwasan -hwasan-use-after-scope=0 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=NOSCOPE
|
||||
|
||||
; ModuleID = 'use-after-scope.c'
|
||||
source_filename = "use-after-scope.c"
|
||||
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
define dso_local i32 @standard_lifetime() local_unnamed_addr sanitize_hwaddress {
|
||||
; SCOPE-LABEL: @standard_lifetime(
|
||||
; SCOPE-NEXT: [[DOTHWASAN_SHADOW:%.*]] = call i8* asm "", "=r,0"(i8* null)
|
||||
; SCOPE-NEXT: [[TMP1:%.*]] = alloca { i8, [15 x i8] }, align 16
|
||||
; SCOPE-NEXT: [[TMP2:%.*]] = bitcast { i8, [15 x i8] }* [[TMP1]] to i8*
|
||||
; SCOPE-NEXT: [[TMP3:%.*]] = call i8 @__hwasan_generate_tag()
|
||||
; SCOPE-NEXT: [[TMP4:%.*]] = zext i8 [[TMP3]] to i64
|
||||
; SCOPE-NEXT: [[TMP5:%.*]] = ptrtoint i8* [[TMP2]] to i64
|
||||
; SCOPE-NEXT: [[TMP6:%.*]] = shl i64 [[TMP4]], 57
|
||||
; SCOPE-NEXT: [[TMP7:%.*]] = or i64 [[TMP5]], [[TMP6]]
|
||||
; SCOPE-NEXT: [[ALLOCA_0_HWASAN:%.*]] = inttoptr i64 [[TMP7]] to i8*
|
||||
; SCOPE-NEXT: br label [[TMP8:%.*]]
|
||||
; SCOPE: 8:
|
||||
; SCOPE-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[ALLOCA_0_HWASAN]])
|
||||
; SCOPE-NEXT: [[TMP9:%.*]] = trunc i64 [[TMP4]] to i8
|
||||
; SCOPE-NEXT: call void @__hwasan_tag_memory(i8* [[TMP2]], i8 [[TMP9]], i64 16)
|
||||
; SCOPE-NEXT: [[TMP10:%.*]] = tail call i1 (...) @cond()
|
||||
; SCOPE-NEXT: call void @__hwasan_tag_memory(i8* [[TMP2]], i8 0, i64 16)
|
||||
; SCOPE-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[ALLOCA_0_HWASAN]])
|
||||
; SCOPE-NEXT: br i1 [[TMP10]], label [[TMP11:%.*]], label [[TMP8]]
|
||||
; SCOPE: 11:
|
||||
; SCOPE-NEXT: call void @use(i8* nonnull [[ALLOCA_0_HWASAN]])
|
||||
; SCOPE-NEXT: ret i32 0
|
||||
;
|
||||
; NOSCOPE-LABEL: @standard_lifetime(
|
||||
; NOSCOPE-NEXT: [[DOTHWASAN_SHADOW:%.*]] = call i8* asm "", "=r,0"(i8* null)
|
||||
; NOSCOPE-NEXT: [[TMP1:%.*]] = alloca { i8, [15 x i8] }, align 16
|
||||
; NOSCOPE-NEXT: [[TMP2:%.*]] = bitcast { i8, [15 x i8] }* [[TMP1]] to i8*
|
||||
; NOSCOPE-NEXT: [[TMP3:%.*]] = call i8 @__hwasan_generate_tag()
|
||||
; NOSCOPE-NEXT: [[TMP4:%.*]] = zext i8 [[TMP3]] to i64
|
||||
; NOSCOPE-NEXT: [[TMP5:%.*]] = ptrtoint i8* [[TMP2]] to i64
|
||||
; NOSCOPE-NEXT: [[TMP6:%.*]] = shl i64 [[TMP4]], 57
|
||||
; NOSCOPE-NEXT: [[TMP7:%.*]] = or i64 [[TMP5]], [[TMP6]]
|
||||
; NOSCOPE-NEXT: [[ALLOCA_0_HWASAN:%.*]] = inttoptr i64 [[TMP7]] to i8*
|
||||
; NOSCOPE-NEXT: [[TMP8:%.*]] = trunc i64 [[TMP4]] to i8
|
||||
; NOSCOPE-NEXT: call void @__hwasan_tag_memory(i8* [[TMP2]], i8 [[TMP8]], i64 16)
|
||||
; NOSCOPE-NEXT: br label [[TMP9:%.*]]
|
||||
; NOSCOPE: 9:
|
||||
; NOSCOPE-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[ALLOCA_0_HWASAN]])
|
||||
; NOSCOPE-NEXT: [[TMP10:%.*]] = tail call i1 (...) @cond()
|
||||
; NOSCOPE-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[ALLOCA_0_HWASAN]])
|
||||
; NOSCOPE-NEXT: br i1 [[TMP10]], label [[TMP11:%.*]], label [[TMP9]]
|
||||
; NOSCOPE: 11:
|
||||
; NOSCOPE-NEXT: call void @use(i8* nonnull [[ALLOCA_0_HWASAN]])
|
||||
; NOSCOPE-NEXT: call void @__hwasan_tag_memory(i8* [[TMP2]], i8 0, i64 16)
|
||||
; NOSCOPE-NEXT: ret i32 0
|
||||
;
|
||||
%1 = alloca i8, align 1
|
||||
br label %2
|
||||
|
||||
2: ; preds = %2, %0
|
||||
; We should tag the memory after the br (in the loop).
|
||||
call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %1)
|
||||
%3 = tail call i1 (...) @cond() #2
|
||||
; We should tag the memory before the next br (before the jump back).
|
||||
call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %1)
|
||||
br i1 %3, label %4, label %2
|
||||
|
||||
4: ; preds = %2
|
||||
call void @use(i8* nonnull %1) #2
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define dso_local i32 @multiple_lifetimes() local_unnamed_addr sanitize_hwaddress {
|
||||
; SCOPE-LABEL: @multiple_lifetimes(
|
||||
; SCOPE-NEXT: [[DOTHWASAN_SHADOW:%.*]] = call i8* asm "", "=r,0"(i8* null)
|
||||
; SCOPE-NEXT: [[TMP1:%.*]] = alloca { i8, [15 x i8] }, align 16
|
||||
; SCOPE-NEXT: [[TMP2:%.*]] = bitcast { i8, [15 x i8] }* [[TMP1]] to i8*
|
||||
; SCOPE-NEXT: [[TMP3:%.*]] = call i8 @__hwasan_generate_tag()
|
||||
; SCOPE-NEXT: [[TMP4:%.*]] = zext i8 [[TMP3]] to i64
|
||||
; SCOPE-NEXT: [[TMP5:%.*]] = ptrtoint i8* [[TMP2]] to i64
|
||||
; SCOPE-NEXT: [[TMP6:%.*]] = shl i64 [[TMP4]], 57
|
||||
; SCOPE-NEXT: [[TMP7:%.*]] = or i64 [[TMP5]], [[TMP6]]
|
||||
; SCOPE-NEXT: [[ALLOCA_0_HWASAN:%.*]] = inttoptr i64 [[TMP7]] to i8*
|
||||
; SCOPE-NEXT: [[TMP8:%.*]] = trunc i64 [[TMP4]] to i8
|
||||
; SCOPE-NEXT: call void @__hwasan_tag_memory(i8* [[TMP2]], i8 [[TMP8]], i64 16)
|
||||
; SCOPE-NEXT: call void @use(i8* nonnull [[ALLOCA_0_HWASAN]])
|
||||
; SCOPE-NEXT: call void @use(i8* nonnull [[ALLOCA_0_HWASAN]])
|
||||
; SCOPE-NEXT: call void @__hwasan_tag_memory(i8* [[TMP2]], i8 0, i64 16)
|
||||
; SCOPE-NEXT: ret i32 0
|
||||
;
|
||||
; NOSCOPE-LABEL: @multiple_lifetimes(
|
||||
; NOSCOPE-NEXT: [[DOTHWASAN_SHADOW:%.*]] = call i8* asm "", "=r,0"(i8* null)
|
||||
; NOSCOPE-NEXT: [[TMP1:%.*]] = alloca { i8, [15 x i8] }, align 16
|
||||
; NOSCOPE-NEXT: [[TMP2:%.*]] = bitcast { i8, [15 x i8] }* [[TMP1]] to i8*
|
||||
; NOSCOPE-NEXT: [[TMP3:%.*]] = call i8 @__hwasan_generate_tag()
|
||||
; NOSCOPE-NEXT: [[TMP4:%.*]] = zext i8 [[TMP3]] to i64
|
||||
; NOSCOPE-NEXT: [[TMP5:%.*]] = ptrtoint i8* [[TMP2]] to i64
|
||||
; NOSCOPE-NEXT: [[TMP6:%.*]] = shl i64 [[TMP4]], 57
|
||||
; NOSCOPE-NEXT: [[TMP7:%.*]] = or i64 [[TMP5]], [[TMP6]]
|
||||
; NOSCOPE-NEXT: [[ALLOCA_0_HWASAN:%.*]] = inttoptr i64 [[TMP7]] to i8*
|
||||
; NOSCOPE-NEXT: [[TMP8:%.*]] = trunc i64 [[TMP4]] to i8
|
||||
; NOSCOPE-NEXT: call void @__hwasan_tag_memory(i8* [[TMP2]], i8 [[TMP8]], i64 16)
|
||||
; NOSCOPE-NEXT: call void @use(i8* nonnull [[ALLOCA_0_HWASAN]])
|
||||
; NOSCOPE-NEXT: call void @use(i8* nonnull [[ALLOCA_0_HWASAN]])
|
||||
; NOSCOPE-NEXT: call void @__hwasan_tag_memory(i8* [[TMP2]], i8 0, i64 16)
|
||||
; NOSCOPE-NEXT: ret i32 0
|
||||
;
|
||||
%1 = alloca i8, align 1
|
||||
; We erase lifetime markers if we insert instrumentation outside of the
|
||||
; lifetime.
|
||||
call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %1)
|
||||
call void @use(i8* nonnull %1) #2
|
||||
call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %1)
|
||||
call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %1)
|
||||
call void @use(i8* nonnull %1) #2
|
||||
call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %1)
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define dso_local i32 @unreachable_exit() local_unnamed_addr sanitize_hwaddress {
|
||||
; SCOPE-LABEL: @unreachable_exit(
|
||||
; SCOPE-NEXT: [[DOTHWASAN_SHADOW:%.*]] = call i8* asm "", "=r,0"(i8* null)
|
||||
; SCOPE-NEXT: [[TMP1:%.*]] = alloca { i8, [15 x i8] }, align 16
|
||||
; SCOPE-NEXT: [[TMP2:%.*]] = bitcast { i8, [15 x i8] }* [[TMP1]] to i8*
|
||||
; SCOPE-NEXT: [[TMP3:%.*]] = call i8 @__hwasan_generate_tag()
|
||||
; SCOPE-NEXT: [[TMP4:%.*]] = zext i8 [[TMP3]] to i64
|
||||
; SCOPE-NEXT: [[TMP5:%.*]] = ptrtoint i8* [[TMP2]] to i64
|
||||
; SCOPE-NEXT: [[TMP6:%.*]] = shl i64 [[TMP4]], 57
|
||||
; SCOPE-NEXT: [[TMP7:%.*]] = or i64 [[TMP5]], [[TMP6]]
|
||||
; SCOPE-NEXT: [[ALLOCA_0_HWASAN:%.*]] = inttoptr i64 [[TMP7]] to i8*
|
||||
; SCOPE-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[ALLOCA_0_HWASAN]])
|
||||
; SCOPE-NEXT: [[TMP8:%.*]] = trunc i64 [[TMP4]] to i8
|
||||
; SCOPE-NEXT: call void @__hwasan_tag_memory(i8* [[TMP2]], i8 [[TMP8]], i64 16)
|
||||
; SCOPE-NEXT: [[TMP9:%.*]] = tail call i1 (...) @cond()
|
||||
; SCOPE-NEXT: br i1 [[TMP9]], label [[TMP10:%.*]], label [[TMP11:%.*]]
|
||||
; SCOPE: 10:
|
||||
; SCOPE-NEXT: call void @use(i8* nonnull [[ALLOCA_0_HWASAN]])
|
||||
; SCOPE-NEXT: call void @__hwasan_tag_memory(i8* [[TMP2]], i8 0, i64 16)
|
||||
; SCOPE-NEXT: ret i32 0
|
||||
; SCOPE: 11:
|
||||
; SCOPE-NEXT: call void @__hwasan_tag_memory(i8* [[TMP2]], i8 0, i64 16)
|
||||
; SCOPE-NEXT: ret i32 0
|
||||
;
|
||||
; NOSCOPE-LABEL: @unreachable_exit(
|
||||
; NOSCOPE-NEXT: [[DOTHWASAN_SHADOW:%.*]] = call i8* asm "", "=r,0"(i8* null)
|
||||
; NOSCOPE-NEXT: [[TMP1:%.*]] = alloca { i8, [15 x i8] }, align 16
|
||||
; NOSCOPE-NEXT: [[TMP2:%.*]] = bitcast { i8, [15 x i8] }* [[TMP1]] to i8*
|
||||
; NOSCOPE-NEXT: [[TMP3:%.*]] = call i8 @__hwasan_generate_tag()
|
||||
; NOSCOPE-NEXT: [[TMP4:%.*]] = zext i8 [[TMP3]] to i64
|
||||
; NOSCOPE-NEXT: [[TMP5:%.*]] = ptrtoint i8* [[TMP2]] to i64
|
||||
; NOSCOPE-NEXT: [[TMP6:%.*]] = shl i64 [[TMP4]], 57
|
||||
; NOSCOPE-NEXT: [[TMP7:%.*]] = or i64 [[TMP5]], [[TMP6]]
|
||||
; NOSCOPE-NEXT: [[ALLOCA_0_HWASAN:%.*]] = inttoptr i64 [[TMP7]] to i8*
|
||||
; NOSCOPE-NEXT: [[TMP8:%.*]] = trunc i64 [[TMP4]] to i8
|
||||
; NOSCOPE-NEXT: call void @__hwasan_tag_memory(i8* [[TMP2]], i8 [[TMP8]], i64 16)
|
||||
; NOSCOPE-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[ALLOCA_0_HWASAN]])
|
||||
; NOSCOPE-NEXT: [[TMP9:%.*]] = tail call i1 (...) @cond()
|
||||
; NOSCOPE-NEXT: br i1 [[TMP9]], label [[TMP10:%.*]], label [[TMP11:%.*]]
|
||||
; NOSCOPE: 10:
|
||||
; NOSCOPE-NEXT: call void @use(i8* nonnull [[ALLOCA_0_HWASAN]])
|
||||
; NOSCOPE-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[ALLOCA_0_HWASAN]])
|
||||
; NOSCOPE-NEXT: call void @__hwasan_tag_memory(i8* [[TMP2]], i8 0, i64 16)
|
||||
; NOSCOPE-NEXT: ret i32 0
|
||||
; NOSCOPE: 11:
|
||||
; NOSCOPE-NEXT: call void @__hwasan_tag_memory(i8* [[TMP2]], i8 0, i64 16)
|
||||
; NOSCOPE-NEXT: ret i32 0
|
||||
;
|
||||
%1 = alloca i8, align 1
|
||||
call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %1)
|
||||
%2 = tail call i1 (...) @cond() #2
|
||||
br i1 %2, label %3, label %4
|
||||
|
||||
3:
|
||||
call void @use(i8* nonnull %1) #2
|
||||
call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %1)
|
||||
ret i32 0
|
||||
|
||||
4:
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
declare dso_local i1 @cond(...) local_unnamed_addr
|
||||
|
||||
declare dso_local void @use(i8*) local_unnamed_addr
|
||||
|
||||
; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn
|
||||
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture)
|
||||
|
||||
; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn
|
||||
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture)
|
Loading…
Reference in New Issue