[compiler-rt] 84705ed - [hwasan] Detect use after scope within function.

Florian Mayer via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 30 05:59:44 PDT 2021


Author: Florian Mayer
Date: 2021-07-30T13:59:36+01:00
New Revision: 84705ed913659d1d5e0ee6b5ae7b298914ec87d4

URL: https://github.com/llvm/llvm-project/commit/84705ed913659d1d5e0ee6b5ae7b298914ec87d4
DIFF: https://github.com/llvm/llvm-project/commit/84705ed913659d1d5e0ee6b5ae7b298914ec87d4.diff

LOG: [hwasan] Detect use after scope within function.

Reviewed By: vitalybuka

Differential Revision: https://reviews.llvm.org/D105201

Added: 
    compiler-rt/test/hwasan/TestCases/stack-uas.c
    llvm/test/Instrumentation/HWAddressSanitizer/use-after-scope.ll

Modified: 
    compiler-rt/test/hwasan/TestCases/use-after-scope-capture.cpp
    compiler-rt/test/hwasan/TestCases/use-after-scope-dtor-order.cpp
    compiler-rt/test/hwasan/TestCases/use-after-scope-goto.cpp
    compiler-rt/test/hwasan/TestCases/use-after-scope-if.cpp
    compiler-rt/test/hwasan/TestCases/use-after-scope-inlined.cpp
    compiler-rt/test/hwasan/TestCases/use-after-scope-loop-bug.cpp
    compiler-rt/test/hwasan/TestCases/use-after-scope-loop-removed.cpp
    compiler-rt/test/hwasan/TestCases/use-after-scope-loop.cpp
    compiler-rt/test/hwasan/TestCases/use-after-scope-nobug.cpp
    compiler-rt/test/hwasan/TestCases/use-after-scope-temp.cpp
    compiler-rt/test/hwasan/TestCases/use-after-scope-temp2.cpp
    compiler-rt/test/hwasan/TestCases/use-after-scope-types.cpp
    compiler-rt/test/hwasan/TestCases/use-after-scope.cpp
    llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/test/hwasan/TestCases/stack-uas.c b/compiler-rt/test/hwasan/TestCases/stack-uas.c
new file mode 100644
index 0000000000000..2f501b33eb919
--- /dev/null
+++ b/compiler-rt/test/hwasan/TestCases/stack-uas.c
@@ -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
+}

diff  --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-capture.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-capture.cpp
index de602f070cf85..a12fa12dbd973 100644
--- a/compiler-rt/test/hwasan/TestCases/use-after-scope-capture.cpp
+++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-capture.cpp
@@ -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

diff  --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-dtor-order.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-dtor-order.cpp
index 41d419a844587..c0096bb8e5bcf 100644
--- a/compiler-rt/test/hwasan/TestCases/use-after-scope-dtor-order.cpp
+++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-dtor-order.cpp
@@ -1,8 +1,9 @@
-// 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
 
 #include <stdio.h>
 
@@ -10,7 +11,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; }

diff  --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-goto.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-goto.cpp
index 37d6732ef1463..d357d38a5906c 100644
--- a/compiler-rt/test/hwasan/TestCases/use-after-scope-goto.cpp
+++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-goto.cpp
@@ -1,10 +1,11 @@
-// 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
 
 #include <stdlib.h>
 

diff  --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-if.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-if.cpp
index 916b8de62762d..b1729d00f1c91 100644
--- a/compiler-rt/test/hwasan/TestCases/use-after-scope-if.cpp
+++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-if.cpp
@@ -1,8 +1,9 @@
-// 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
 
 int *p;
 bool b = true;
@@ -13,6 +14,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
 }

diff  --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-inlined.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-inlined.cpp
index 0ce8d2f9c0695..447d9c8426c32 100644
--- a/compiler-rt/test/hwasan/TestCases/use-after-scope-inlined.cpp
+++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-inlined.cpp
@@ -1,15 +1,15 @@
+// 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: *
 
-int *arr;
+// REQUIRES: aarch64-target-arch
 
+int *arr;
 __attribute__((always_inline)) void inlined(int arg) {
   int x[5];
   for (int i = 0; i < arg; i++)
@@ -20,12 +20,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
 }

diff  --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-loop-bug.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-loop-bug.cpp
index 2392230811f4f..37372709116ff 100644
--- a/compiler-rt/test/hwasan/TestCases/use-after-scope-loop-bug.cpp
+++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-loop-bug.cpp
@@ -1,8 +1,9 @@
-// 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
 
 volatile int *p;
 
@@ -13,8 +14,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
 }

diff  --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-loop-removed.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-loop-removed.cpp
index 708f17aeab344..f32e09c67990b 100644
--- a/compiler-rt/test/hwasan/TestCases/use-after-scope-loop-removed.cpp
+++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-loop-removed.cpp
@@ -1,8 +1,9 @@
-// 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
 
 #include <stdlib.h>
 
@@ -14,8 +15,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
 }

diff  --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-loop.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-loop.cpp
index 6f3d404e919b7..b28f05cc8d132 100644
--- a/compiler-rt/test/hwasan/TestCases/use-after-scope-loop.cpp
+++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-loop.cpp
@@ -1,8 +1,9 @@
-// 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
 
 int *p[3];
 
@@ -12,6 +13,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
 }

diff  --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-nobug.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-nobug.cpp
index a3de37c79ce6d..ce0ff1b78d0b1 100644
--- a/compiler-rt/test/hwasan/TestCases/use-after-scope-nobug.cpp
+++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-nobug.cpp
@@ -1,7 +1,8 @@
-// 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
 
 #include <stdio.h>
 #include <stdlib.h>

diff  --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-temp.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-temp.cpp
index 39fec6b29f693..b47461b7e0075 100644
--- a/compiler-rt/test/hwasan/TestCases/use-after-scope-temp.cpp
+++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-temp.cpp
@@ -1,8 +1,9 @@
-// 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
 
 struct IntHolder {
   int val;
@@ -17,7 +18,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;
 }

diff  --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-temp2.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-temp2.cpp
index 93f8bfe2a999a..754cc23e6329c 100644
--- a/compiler-rt/test/hwasan/TestCases/use-after-scope-temp2.cpp
+++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-temp2.cpp
@@ -1,8 +1,9 @@
-// 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
 
 struct IntHolder {
   __attribute__((noinline)) const IntHolder &Self() const {
@@ -16,7 +17,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;
 }

diff  --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-types.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-types.cpp
index 2800178b87abe..d2424e0f1d6c1 100644
--- a/compiler-rt/test/hwasan/TestCases/use-after-scope-types.cpp
+++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-types.cpp
@@ -1,18 +1,20 @@
-// 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
 
 #include <stdlib.h>
 #include <string>
@@ -46,10 +48,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) {

diff  --git a/compiler-rt/test/hwasan/TestCases/use-after-scope.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope.cpp
index 67e1b8bf0c8d4..b5367d17cc245 100644
--- a/compiler-rt/test/hwasan/TestCases/use-after-scope.cpp
+++ b/compiler-rt/test/hwasan/TestCases/use-after-scope.cpp
@@ -1,12 +1,9 @@
-// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \
-// RUN:     not %run %t 2>&1 | FileCheck %s
+// This is the ASAN test of the same name ported to HWAsan.
 
-// -fsanitize-address-use-after-scope is now on by default:
-// RUN: %clangxx_asan -O1 %s -o %t && \
+// 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
 
 volatile int *p = 0;
 
@@ -16,9 +13,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;
 }

diff  --git a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
index 60a4ee8811fb3..d9b9d82dd4f24 100644
--- a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
@@ -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 @@ class HWAddressSanitizer {
 
   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 @@ class HWAddressSanitizer {
       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 @@ class HWAddressSanitizer {
     void init(Triple &TargetTriple, bool InstrumentWithCalls);
     unsigned getObjectAlignment() const { return 1U << Scale; }
   };
+
   ShadowMapping Mapping;
 
   Type *VoidTy = Type::getVoidTy(M.getContext());
@@ -331,6 +358,7 @@ class HWAddressSanitizer {
   bool InstrumentLandingPads;
   bool InstrumentWithCalls;
   bool InstrumentStack;
+  bool DetectUseAfterScope;
   bool UsePageAliases;
 
   bool HasMatchAllTag = false;
@@ -377,14 +405,21 @@ class HWAddressSanitizerLegacyPass : public FunctionPass {
   }
 
   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 @@ class HWAddressSanitizerLegacyPass : public FunctionPass {
     // 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);
-    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()));
+    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);
+      if (!forAllReachableExits(GetDT(), GetPDT(), Start, End, RetVec, TagEnd))
+        End->eraseFromParent();
+    } else {
+      tagAlloca(IRB, AI, Tag, Size);
+      for (auto *RI : RetVec) {
+        IRB.SetInsertPoint(RI);
+        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(

diff  --git a/llvm/test/Instrumentation/HWAddressSanitizer/use-after-scope.ll b/llvm/test/Instrumentation/HWAddressSanitizer/use-after-scope.ll
new file mode 100644
index 0000000000000..3a4a2bc6d67ca
--- /dev/null
+++ b/llvm/test/Instrumentation/HWAddressSanitizer/use-after-scope.ll
@@ -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)


        


More information about the llvm-commits mailing list