[compiler-rt] 4e67ae7 - [dfsan] Add origin ABI wrappers for thread/signal/fork

Jianzhou Zhao via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 15 09:18:15 PDT 2021


Author: Jianzhou Zhao
Date: 2021-03-15T16:18:00Z
New Revision: 4e67ae7b6b1c6c06f40191d9c968717101903761

URL: https://github.com/llvm/llvm-project/commit/4e67ae7b6b1c6c06f40191d9c968717101903761
DIFF: https://github.com/llvm/llvm-project/commit/4e67ae7b6b1c6c06f40191d9c968717101903761.diff

LOG: [dfsan] Add origin ABI wrappers for thread/signal/fork

This is a part of https://reviews.llvm.org/D95835.

See https://github.com/llvm/llvm-project/commit/bb91e02efd00eda04296069a83228c8d9db105b7 about the similar issue of fork in MSan's origin tracking.

Reviewed By: morehouse

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

Added: 
    compiler-rt/test/dfsan/fork.cpp
    compiler-rt/test/dfsan/origin_with_sigactions.c
    compiler-rt/test/dfsan/origin_with_signals.cpp

Modified: 
    compiler-rt/lib/dfsan/dfsan.cpp
    compiler-rt/lib/dfsan/dfsan_custom.cpp
    compiler-rt/lib/dfsan/dfsan_thread.cpp
    compiler-rt/lib/dfsan/dfsan_thread.h
    compiler-rt/lib/dfsan/done_abilist.txt
    compiler-rt/test/dfsan/atomic.cpp
    compiler-rt/test/dfsan/custom.cpp
    compiler-rt/test/dfsan/pthread.c
    compiler-rt/test/dfsan/sigaction_stress_test.c

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/dfsan/dfsan.cpp b/compiler-rt/lib/dfsan/dfsan.cpp
index da01a63fa86d..5a9620aa417e 100644
--- a/compiler-rt/lib/dfsan/dfsan.cpp
+++ b/compiler-rt/lib/dfsan/dfsan.cpp
@@ -708,6 +708,14 @@ extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label __dfso_dfsan_get_label(
   return data_label;
 }
 
+// This function is used if dfsan_get_origin is called when origin tracking is
+// off.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin __dfsw_dfsan_get_origin(
+    long data, dfsan_label data_label, dfsan_label *ret_label) {
+  *ret_label = 0;
+  return 0;
+}
+
 extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin __dfso_dfsan_get_origin(
     long data, dfsan_label data_label, dfsan_label *ret_label,
     dfsan_origin data_origin, dfsan_origin *ret_origin) {
@@ -847,6 +855,7 @@ dfsan_get_init_origin(const void *addr) {
   dfsan_origin origin_id = o.raw_id();
   while (o.isChainedOrigin()) {
     StackTrace stack;
+    origin_id = o.raw_id();
     o = o.getNextChainedOrigin(&stack);
   }
   return origin_id;

diff  --git a/compiler-rt/lib/dfsan/dfsan_custom.cpp b/compiler-rt/lib/dfsan/dfsan_custom.cpp
index 72c1065939d0..ae0c46ac9b71 100644
--- a/compiler-rt/lib/dfsan/dfsan_custom.cpp
+++ b/compiler-rt/lib/dfsan/dfsan_custom.cpp
@@ -37,10 +37,12 @@
 #include <unistd.h>
 
 #include "dfsan/dfsan.h"
+#include "dfsan/dfsan_chained_origin_depot.h"
 #include "dfsan/dfsan_thread.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_linux.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
 
 using namespace __dfsan;
 
@@ -310,6 +312,17 @@ __dfsw_strlen(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
   return ret;
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE size_t __dfso_strlen(const char *s,
+                                                   dfsan_label s_label,
+                                                   dfsan_label *ret_label,
+                                                   dfsan_origin s_origin,
+                                                   dfsan_origin *ret_origin) {
+  size_t ret = __dfsw_strlen(s, s_label, ret_label);
+  if (!flags().strict_data_dependencies)
+    *ret_origin = dfsan_read_origin_of_first_taint(s, ret + 1);
+  return ret;
+}
+
 static void *dfsan_memmove(void *dest, const void *src, size_t n) {
   dfsan_label *sdest = shadow_for(dest);
   const dfsan_label *ssrc = shadow_for(src);
@@ -456,7 +469,8 @@ static void *DFsanThreadStartFunc(void *arg) {
 static int dfsan_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                                 void *start_routine_trampoline,
                                 void *start_routine, void *arg,
-                                dfsan_label *ret_label) {
+                                dfsan_label *ret_label,
+                                bool track_origins = false) {
   pthread_attr_t myattr;
   if (!attr) {
     pthread_attr_init(&myattr);
@@ -466,8 +480,9 @@ static int dfsan_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
   // Ensure that the thread stack is large enough to hold all TLS data.
   AdjustStackSize((void *)(const_cast<pthread_attr_t *>(attr)));
 
-  DFsanThread *t = DFsanThread::Create(start_routine_trampoline,
-                                       (thread_callback_t)start_routine, arg);
+  DFsanThread *t =
+      DFsanThread::Create(start_routine_trampoline,
+                          (thread_callback_t)start_routine, arg, track_origins);
   int res = pthread_create(thread, attr, DFsanThreadStartFunc, t);
 
   if (attr == &myattr)
@@ -487,6 +502,20 @@ SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_create(
                               start_routine, arg, ret_label);
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_create(
+    pthread_t *thread, const pthread_attr_t *attr,
+    void *(*start_routine_trampoline)(void *, void *, dfsan_label,
+                                      dfsan_label *, dfsan_origin,
+                                      dfsan_origin *),
+    void *start_routine, void *arg, dfsan_label thread_label,
+    dfsan_label attr_label, dfsan_label start_routine_label,
+    dfsan_label arg_label, dfsan_label *ret_label, dfsan_origin thread_origin,
+    dfsan_origin attr_origin, dfsan_origin start_routine_origin,
+    dfsan_origin arg_origin, dfsan_origin *ret_origin) {
+  return dfsan_pthread_create(thread, attr, (void *)start_routine_trampoline,
+                              start_routine, arg, ret_label, true);
+}
+
 SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_join(pthread_t thread,
                                                       void **retval,
                                                       dfsan_label thread_label,
@@ -499,6 +528,15 @@ SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_join(pthread_t thread,
   return ret;
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_join(
+    pthread_t thread, void **retval, dfsan_label thread_label,
+    dfsan_label retval_label, dfsan_label *ret_label,
+    dfsan_origin thread_origin, dfsan_origin retval_origin,
+    dfsan_origin *ret_origin) {
+  return __dfsw_pthread_join(thread, retval, thread_label, retval_label,
+                             ret_label);
+}
+
 struct dl_iterate_phdr_info {
   int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
                              size_t size, void *data, dfsan_label info_label,
@@ -872,6 +910,13 @@ int __dfsw_sigemptyset(sigset_t *set, dfsan_label set_label,
   return ret;
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfso_sigemptyset(sigset_t *set, dfsan_label set_label,
+                       dfsan_label *ret_label, dfsan_origin set_origin,
+                       dfsan_origin *ret_origin) {
+  return __dfsw_sigemptyset(set, set_label, ret_label);
+}
+
 class SignalHandlerScope {
  public:
   SignalHandlerScope() {
@@ -988,11 +1033,18 @@ int __dfsw_sigaction(int signum, const struct sigaction *act,
 }
 
 SANITIZER_INTERFACE_ATTRIBUTE
-sighandler_t __dfsw_signal(int signum,
-                           void *(*handler_trampoline)(void *, int, dfsan_label,
-                                                       dfsan_label *),
-                           sighandler_t handler, dfsan_label signum_label,
-                           dfsan_label handler_label, dfsan_label *ret_label) {
+int __dfso_sigaction(int signum, const struct sigaction *act,
+                     struct sigaction *oldact, dfsan_label signum_label,
+                     dfsan_label act_label, dfsan_label oldact_label,
+                     dfsan_label *ret_label, dfsan_origin signum_origin,
+                     dfsan_origin act_origin, dfsan_origin oldact_origin,
+                     dfsan_origin *ret_origin) {
+  return __dfsw_sigaction(signum, act, oldact, signum_label, act_label,
+                          oldact_label, ret_label);
+}
+
+static sighandler_t dfsan_signal(int signum, sighandler_t handler,
+                                 dfsan_label *ret_label) {
   CHECK_LT(signum, kMaxSignals);
   SignalSpinLocker lock;
   uptr old_cb = atomic_load(&sigactions[signum], memory_order_relaxed);
@@ -1010,6 +1062,26 @@ sighandler_t __dfsw_signal(int signum,
   return ret;
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE
+sighandler_t __dfsw_signal(int signum,
+                           void *(*handler_trampoline)(void *, int, dfsan_label,
+                                                       dfsan_label *),
+                           sighandler_t handler, dfsan_label signum_label,
+                           dfsan_label handler_label, dfsan_label *ret_label) {
+  return dfsan_signal(signum, handler, ret_label);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+sighandler_t __dfso_signal(
+    int signum,
+    void *(*handler_trampoline)(void *, int, dfsan_label, dfsan_label *,
+                                dfsan_origin, dfsan_origin *),
+    sighandler_t handler, dfsan_label signum_label, dfsan_label handler_label,
+    dfsan_label *ret_label, dfsan_origin signum_origin,
+    dfsan_origin handler_origin, dfsan_origin *ret_origin) {
+  return dfsan_signal(signum, handler, ret_label);
+}
+
 SANITIZER_INTERFACE_ATTRIBUTE
 int __dfsw_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label,
                        dfsan_label old_ss_label, dfsan_label *ret_label) {
@@ -1020,6 +1092,14 @@ int __dfsw_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label,
   return ret;
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE
+int __dfso_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label,
+                       dfsan_label old_ss_label, dfsan_label *ret_label,
+                       dfsan_origin ss_origin, dfsan_origin old_ss_origin,
+                       dfsan_origin *ret_origin) {
+  return __dfsw_sigaltstack(ss, old_ss, ss_label, old_ss_label, ret_label);
+}
+
 SANITIZER_INTERFACE_ATTRIBUTE
 int __dfsw_gettimeofday(struct timeval *tv, struct timezone *tz,
                         dfsan_label tv_label, dfsan_label tz_label,
@@ -1203,6 +1283,11 @@ typedef void (*write_trampoline_t)(
     int fd, const void *buf, ssize_t count,
     dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label);
 
+typedef void (*write_origin_trampoline_t)(
+    void *callback, int fd, const void *buf, ssize_t count,
+    dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label,
+    dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin);
+
 // Calls to dfsan_set_write_callback() set the values in this struct.
 // Calls to the custom version of write() read (and invoke) them.
 static struct {
@@ -1210,6 +1295,11 @@ static struct {
   void *write_callback = nullptr;
 } write_callback_info;
 
+static struct {
+  write_origin_trampoline_t write_callback_trampoline = nullptr;
+  void *write_callback = nullptr;
+} write_origin_callback_info;
+
 SANITIZER_INTERFACE_ATTRIBUTE void
 __dfsw_dfsan_set_write_callback(
     write_trampoline_t write_callback_trampoline,
@@ -1220,6 +1310,15 @@ __dfsw_dfsan_set_write_callback(
   write_callback_info.write_callback = write_callback;
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE void __dfso_dfsan_set_write_callback(
+    write_origin_trampoline_t write_callback_trampoline, void *write_callback,
+    dfsan_label write_callback_label, dfsan_label *ret_label,
+    dfsan_origin write_callback_origin, dfsan_origin *ret_origin) {
+  write_origin_callback_info.write_callback_trampoline =
+      write_callback_trampoline;
+  write_origin_callback_info.write_callback = write_callback;
+}
+
 SANITIZER_INTERFACE_ATTRIBUTE int
 __dfsw_write(int fd, const void *buf, size_t count,
              dfsan_label fd_label, dfsan_label buf_label,
@@ -1234,6 +1333,21 @@ __dfsw_write(int fd, const void *buf, size_t count,
   *ret_label = 0;
   return write(fd, buf, count);
 }
+
+SANITIZER_INTERFACE_ATTRIBUTE int __dfso_write(
+    int fd, const void *buf, size_t count, dfsan_label fd_label,
+    dfsan_label buf_label, dfsan_label count_label, dfsan_label *ret_label,
+    dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin,
+    dfsan_origin *ret_origin) {
+  if (write_origin_callback_info.write_callback) {
+    write_origin_callback_info.write_callback_trampoline(
+        write_origin_callback_info.write_callback, fd, buf, count, fd_label,
+        buf_label, count_label, fd_origin, buf_origin, count_origin);
+  }
+
+  *ret_label = 0;
+  return write(fd, buf, count);
+}
 } // namespace __dfsan
 
 // Type used to extract a dfsan_label with va_arg()
@@ -1491,6 +1605,31 @@ int __dfsw_snprintf(char *str, size_t size, const char *format,
   return ret;
 }
 
+static void BeforeFork() {
+  StackDepotLockAll();
+  GetChainedOriginDepot()->LockAll();
+}
+
+static void AfterFork() {
+  GetChainedOriginDepot()->UnlockAll();
+  StackDepotUnlockAll();
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+pid_t __dfsw_fork(dfsan_label *ret_label) {
+  pid_t pid = fork();
+  *ret_label = 0;
+  return pid;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+pid_t __dfso_fork(dfsan_label *ret_label, dfsan_origin *ret_origin) {
+  BeforeFork();
+  pid_t pid = __dfsw_fork(ret_label);
+  AfterFork();
+  return pid;
+}
+
 // Default empty implementations (weak). Users should redefine them.
 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *) {}
 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, u32 *,

diff  --git a/compiler-rt/lib/dfsan/dfsan_thread.cpp b/compiler-rt/lib/dfsan/dfsan_thread.cpp
index 7fd9c8eff350..aa1209aafc33 100644
--- a/compiler-rt/lib/dfsan/dfsan_thread.cpp
+++ b/compiler-rt/lib/dfsan/dfsan_thread.cpp
@@ -7,13 +7,15 @@
 namespace __dfsan {
 
 DFsanThread *DFsanThread::Create(void *start_routine_trampoline,
-                                 thread_callback_t start_routine, void *arg) {
+                                 thread_callback_t start_routine, void *arg,
+                                 bool track_origins) {
   uptr PageSize = GetPageSizeCached();
   uptr size = RoundUpTo(sizeof(DFsanThread), PageSize);
   DFsanThread *thread = (DFsanThread *)MmapOrDie(size, __func__);
   thread->start_routine_trampoline_ = start_routine_trampoline;
   thread->start_routine_ = start_routine;
   thread->arg_ = arg;
+  thread->track_origins_ = track_origins;
   thread->destructor_iterations_ = GetPthreadDestructorIterations();
 
   return thread;
@@ -57,11 +59,19 @@ thread_return_t DFsanThread::ThreadStart() {
 
   typedef void *(*thread_callback_trampoline_t)(void *, void *, dfsan_label,
                                                 dfsan_label *);
+  typedef void *(*thread_callback_origin_trampoline_t)(
+      void *, void *, dfsan_label, dfsan_label *, dfsan_origin, dfsan_origin *);
 
   dfsan_label ret_label;
-  return ((thread_callback_trampoline_t)
+  if (!track_origins_)
+    return ((thread_callback_trampoline_t)
+                start_routine_trampoline_)((void *)start_routine_, arg_, 0,
+                                           &ret_label);
+
+  dfsan_origin ret_origin;
+  return ((thread_callback_origin_trampoline_t)
               start_routine_trampoline_)((void *)start_routine_, arg_, 0,
-                                         &ret_label);
+                                         &ret_label, 0, &ret_origin);
 }
 
 DFsanThread::StackBounds DFsanThread::GetStackBounds() const {

diff  --git a/compiler-rt/lib/dfsan/dfsan_thread.h b/compiler-rt/lib/dfsan/dfsan_thread.h
index c28f1dfd47da..616bbc52661c 100644
--- a/compiler-rt/lib/dfsan/dfsan_thread.h
+++ b/compiler-rt/lib/dfsan/dfsan_thread.h
@@ -24,7 +24,8 @@ class DFsanThread {
   // via mmap() and *must* be valid in zero-initialized state.
 
   static DFsanThread *Create(void *start_routine_trampoline,
-                             thread_callback_t start_routine, void *arg);
+                             thread_callback_t start_routine, void *arg,
+                             bool track_origins = false);
   static void TSDDtor(void *tsd);
   void Destroy();
 
@@ -54,6 +55,7 @@ class DFsanThread {
   void *start_routine_trampoline_;
   thread_callback_t start_routine_;
   void *arg_;
+  bool track_origins_;
 
   StackBounds stack_;
 

diff  --git a/compiler-rt/lib/dfsan/done_abilist.txt b/compiler-rt/lib/dfsan/done_abilist.txt
index 1c993aa0b533..7b392fad2e1d 100644
--- a/compiler-rt/lib/dfsan/done_abilist.txt
+++ b/compiler-rt/lib/dfsan/done_abilist.txt
@@ -30,6 +30,8 @@ fun:dfsan_flush=uninstrumented
 fun:dfsan_flush=discard
 fun:dfsan_print_origin_trace=uninstrumented
 fun:dfsan_print_origin_trace=discard
+fun:dfsan_get_origin=uninstrumented
+fun:dfsan_get_origin=custom
 fun:dfsan_get_init_origin=uninstrumented
 fun:dfsan_get_init_origin=discard
 
@@ -270,6 +272,9 @@ fun:snprintf=custom
 fun:asprintf=discard
 fun:qsort=discard
 
+# fork
+fun:fork=custom
+
 ###############################################################################
 # pthread
 ###############################################################################

diff  --git a/compiler-rt/test/dfsan/atomic.cpp b/compiler-rt/test/dfsan/atomic.cpp
index 7d4dc04cb536..459bf31075e5 100644
--- a/compiler-rt/test/dfsan/atomic.cpp
+++ b/compiler-rt/test/dfsan/atomic.cpp
@@ -1,4 +1,7 @@
 // RUN: %clangxx_dfsan -mllvm -dfsan-fast-16-labels=true %s -fno-exceptions -o %t && %run %t
+// RUN: %clangxx_dfsan -DORIGIN_TRACKING -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -fno-exceptions -o %t && %run %t
+//
+// REQUIRES: x86_64-target-arch
 //
 // Use -fno-exceptions to turn off exceptions to avoid instrumenting
 // __cxa_begin_catch, std::terminate and __gxx_personality_v0.
@@ -14,31 +17,45 @@
 
 std::atomic<int> atomic_i{0};
 
+struct arg_struct {
+  size_t index;
+  dfsan_origin origin;
+};
+
 static void *ThreadFn(void *arg) {
-  if ((size_t)arg % 2) {
+  if (((arg_struct *)arg)->index % 2) {
     int i = 10;
     dfsan_set_label(8, (void *)&i, sizeof(i));
     atomic_i.store(i, std::memory_order_relaxed);
-
     return 0;
   }
   int j = atomic_i.load();
   assert(dfsan_get_label(j) == 0 || dfsan_get_label(j) == 2);
-
+#ifdef ORIGIN_TRACKING
+  if (dfsan_get_label(j) == 2)
+    assert(dfsan_get_init_origin(&j) == ((arg_struct *)arg)->origin);
+#endif
   return 0;
 }
 
 int main(void) {
   int i = 10;
   dfsan_set_label(2, (void *)&i, sizeof(i));
+#ifdef ORIGIN_TRACKING
+  dfsan_origin origin = dfsan_get_origin(i);
+#endif
   atomic_i.store(i, std::memory_order_relaxed);
   const int kNumThreads = 24;
   pthread_t t[kNumThreads];
+  arg_struct args[kNumThreads];
   for (int i = 0; i < kNumThreads; ++i) {
-    pthread_create(&t[i], 0, ThreadFn, (void *)i);
+    args[i].index = i;
+#ifdef ORIGIN_TRACKING
+    args[i].origin = origin;
+#endif
+    pthread_create(&t[i], 0, ThreadFn, (void *)(args + i));
   }
-  for (int i = 0; i < kNumThreads; ++i) {
+  for (int i = 0; i < kNumThreads; ++i)
     pthread_join(t[i], 0);
-  }
   return 0;
 }

diff  --git a/compiler-rt/test/dfsan/custom.cpp b/compiler-rt/test/dfsan/custom.cpp
index 4676c91bed0f..b95d74446acd 100644
--- a/compiler-rt/test/dfsan/custom.cpp
+++ b/compiler-rt/test/dfsan/custom.cpp
@@ -3,8 +3,12 @@
 // RUN: %clang_dfsan -DFAST_16_LABELS -mllvm -dfsan-fast-16-labels %s -o %t && DFSAN_OPTIONS="strict_data_dependencies=0" %run %t
 // RUN: %clang_dfsan -DSTRICT_DATA_DEPENDENCIES %s -o %t && %run %t
 // RUN: %clang_dfsan -DSTRICT_DATA_DEPENDENCIES -mllvm -dfsan-args-abi %s -o %t && %run %t
-
+// RUN: %clang_dfsan -DFAST_16_LABELS -DORIGIN_TRACKING -mllvm -dfsan-fast-16-labels -mllvm -dfsan-track-origins=1 -mllvm -dfsan-combine-pointer-labels-on-load=false -DSTRICT_DATA_DEPENDENCIES %s -o %t && %run %t
+// RUN: %clang_dfsan -DFAST_16_LABELS -DORIGIN_TRACKING -mllvm -dfsan-fast-16-labels -mllvm -dfsan-track-origins=1 -mllvm -dfsan-combine-pointer-labels-on-load=false %s -o %t && DFSAN_OPTIONS="strict_data_dependencies=0" %run %t
+//
 // Tests custom implementations of various glibc functions.
+//
+// REQUIRES: x86_64-target-arch
 
 #include <sanitizer/dfsan_interface.h>
 
@@ -35,6 +39,8 @@
 dfsan_label i_label = 0;
 dfsan_label j_label = 0;
 dfsan_label k_label = 0;
+dfsan_label m_label = 0;
+dfsan_label n_label = 0;
 dfsan_label i_j_label = 0;
 
 #define ASSERT_ZERO_LABEL(data) \
@@ -49,6 +55,102 @@ dfsan_label i_j_label = 0;
 #define ASSERT_READ_LABEL(ptr, size, label) \
   assert(label == dfsan_read_label(ptr, size))
 
+#ifdef ORIGIN_TRACKING
+#define ASSERT_ZERO_ORIGIN(data) \
+  assert(0 == dfsan_get_origin((long)(data)))
+#else
+#define ASSERT_ZERO_ORIGIN(data)
+#endif
+
+#ifdef ORIGIN_TRACKING
+#define ASSERT_ZERO_ORIGINS(ptr, size)                       \
+  for (int i = 0; i < size; ++i) {                           \
+    assert(0 == dfsan_get_origin((long)(((char *)ptr)[i]))); \
+  }
+#else
+#define ASSERT_ZERO_ORIGINS(ptr, size)
+#endif
+
+#ifdef ORIGIN_TRACKING
+#define ASSERT_ORIGIN(data, origin) \
+  assert(origin == dfsan_get_origin((long)(data)))
+#else
+#define ASSERT_ORIGIN(data, origin)
+#endif
+
+#ifdef ORIGIN_TRACKING
+#define ASSERT_ORIGINS(ptr, size, origin)                         \
+  for (int i = 0; i < size; ++i) {                                \
+    assert(origin == dfsan_get_origin((long)(((char *)ptr)[i]))); \
+  }
+#define ASSERT_ORIGINS(ptr, size, origin)
+#else
+#endif
+
+#ifdef ORIGIN_TRACKING
+#define ASSERT_INIT_ORIGIN(ptr, origin) \
+  assert(origin == dfsan_get_init_origin(ptr))
+#else
+#define ASSERT_INIT_ORIGIN(ptr, origin)
+#endif
+
+#ifdef ORIGIN_TRACKING
+#define ASSERT_INIT_ORIGIN_EQ_ORIGIN(ptr, data) \
+  assert(dfsan_get_origin((long)(data)) == dfsan_get_init_origin(ptr))
+#else
+#define ASSERT_INIT_ORIGIN_EQ_ORIGIN(ptr, data)
+#endif
+
+#ifdef ORIGIN_TRACKING
+#define ASSERT_INIT_ORIGINS(ptr, size, origin)                  \
+  for (int i = 0; i < size; ++i) {                              \
+    assert(origin == dfsan_get_init_origin(&((char *)ptr)[i])); \
+  }
+#else
+#define ASSERT_INIT_ORIGINS(ptr, size, origin)
+#endif
+
+#ifdef ORIGIN_TRACKING
+#define ASSERT_EQ_ORIGIN(data1, data2) \
+  assert(dfsan_get_origin((long)(data1)) == dfsan_get_origin((long)(data2)))
+#else
+#define ASSERT_EQ_ORIGIN(data1, data2)
+#endif
+
+#ifdef ORIGIN_TRACKING
+#define DEFINE_AND_SAVE_ORIGINS(val)    \
+  dfsan_origin val##_o[sizeof(val)];    \
+  for (int i = 0; i < sizeof(val); ++i) \
+    val##_o[i] = dfsan_get_origin((long)(((char *)(&val))[i]));
+#else
+#define DEFINE_AND_SAVE_ORIGINS(val)
+#endif
+
+#ifdef ORIGIN_TRACKING
+#define SAVE_ORIGINS(val)               \
+  for (int i = 0; i < sizeof(val); ++i) \
+    val##_o[i] = dfsan_get_origin((long)(((char *)(&val))[i]));
+#else
+#define SAVE_ORIGINS(val)
+#endif
+
+#ifdef ORIGIN_TRACKING
+#define ASSERT_SAVED_ORIGINS(val)       \
+  for (int i = 0; i < sizeof(val); ++i) \
+    ASSERT_ORIGIN(((char *)(&val))[i], val##_o[i]);
+#else
+#define ASSERT_SAVED_ORIGINS(val)
+#endif
+
+#ifdef ORIGIN_TRACKING
+#define ASSERT_SAVED_N_ORIGINS(val, n) \
+  for (int i = 0; i < n; ++i)          \
+    ASSERT_ORIGIN(val[i], val##_o[i]);
+#else
+#define ASSERT_SAVED_N_ORIGINS(val, n)
+#endif
+
+#if !defined(ORIGIN_TRACKING)
 void test_stat() {
   int i = 1;
   dfsan_set_label(i_label, &i, sizeof(i));
@@ -175,6 +277,7 @@ void test_strcat() {
   }
   ASSERT_LABEL(dst[11], j_label);
 }
+#endif // !defined(ORIGIN_TRACKING)
 
 void test_strlen() {
   char str1[] = "str1";
@@ -186,9 +289,11 @@ void test_strlen() {
   ASSERT_ZERO_LABEL(rv);
 #else
   ASSERT_LABEL(rv, i_label);
+  ASSERT_EQ_ORIGIN(rv, str1[3]);
 #endif
 }
 
+#if !defined(ORIGIN_TRACKING)
 void test_strdup() {
   char str1[] = "str1";
   dfsan_set_label(i_label, &str1[3], 1);
@@ -835,13 +940,17 @@ void test_sched_getaffinity() {
   assert(ret == 0);
   ASSERT_READ_ZERO_LABEL(&mask, sizeof(mask));
 }
+#endif // !defined(ORIGIN_TRACKING)
 
 void test_sigemptyset() {
   sigset_t set;
   dfsan_set_label(j_label, &set, 1);
+  DEFINE_AND_SAVE_ORIGINS(set)
   int ret = sigemptyset(&set);
   assert(ret == 0);
+  ASSERT_ZERO_LABEL(ret);
   ASSERT_READ_ZERO_LABEL(&set, sizeof(set));
+  ASSERT_SAVED_ORIGINS(set)
 }
 
 static void SignalHandler(int signo) {}
@@ -856,10 +965,12 @@ void test_sigaction() {
   // Set sigaction to be SignalAction, save the last one into origin_act
   struct sigaction origin_act;
   dfsan_set_label(j_label, &origin_act, 1);
+  DEFINE_AND_SAVE_ORIGINS(origin_act)
   int ret = sigaction(SIGUSR1, &newact_with_sigaction, &origin_act);
   assert(ret == 0);
   ASSERT_ZERO_LABEL(ret);
   ASSERT_READ_ZERO_LABEL(&origin_act, sizeof(origin_act));
+  ASSERT_SAVED_ORIGINS(origin_act)
 
   struct sigaction newact_with_sighandler = {};
   newact_with_sighandler.sa_handler = SignalHandler;
@@ -904,12 +1015,15 @@ void test_signal() {
 void test_sigaltstack() {
   stack_t old_altstack = {};
   dfsan_set_label(j_label, &old_altstack, sizeof(old_altstack));
+  DEFINE_AND_SAVE_ORIGINS(old_altstack)
   int ret = sigaltstack(NULL, &old_altstack);
   assert(ret == 0);
   ASSERT_ZERO_LABEL(ret);
   ASSERT_READ_ZERO_LABEL(&old_altstack, sizeof(old_altstack));
+  ASSERT_SAVED_ORIGINS(old_altstack)
 }
 
+#if !defined(ORIGIN_TRACKING)
 void test_gettimeofday() {
   struct timeval tv;
   struct timezone tz;
@@ -920,6 +1034,7 @@ void test_gettimeofday() {
   ASSERT_READ_ZERO_LABEL(&tv, sizeof(tv));
   ASSERT_READ_ZERO_LABEL(&tz, sizeof(tz));
 }
+#endif // !defined(ORIGIN_TRACKING)
 
 void *pthread_create_test_cb(void *p) {
   assert(p == (void *)1);
@@ -929,20 +1044,25 @@ void *pthread_create_test_cb(void *p) {
 
 void test_pthread_create() {
   pthread_t pt;
-  pthread_create(&pt, 0, pthread_create_test_cb, (void *)1);
+  int create_ret = pthread_create(&pt, 0, pthread_create_test_cb, (void *)1);
+  assert(create_ret == 0);
+  ASSERT_ZERO_LABEL(create_ret);
   void *cbrv;
   dfsan_set_label(i_label, &cbrv, sizeof(cbrv));
-  int ret = pthread_join(pt, &cbrv);
-  assert(ret == 0);
+  DEFINE_AND_SAVE_ORIGINS(cbrv)
+  int joint_ret = pthread_join(pt, &cbrv);
+  assert(joint_ret == 0);
   assert(cbrv == (void *)2);
-  ASSERT_ZERO_LABEL(ret);
+  ASSERT_ZERO_LABEL(joint_ret);
   ASSERT_ZERO_LABEL(cbrv);
+  ASSERT_SAVED_ORIGINS(cbrv);
 }
 
 // Tested by test_pthread_create().  This empty function is here to appease the
 // check-wrappers script.
 void test_pthread_join() {}
 
+#if !defined(ORIGIN_TRACKING)
 int dl_iterate_phdr_test_cb(struct dl_phdr_info *info, size_t size,
                             void *data) {
   assert(data == (void *)3);
@@ -1165,6 +1285,7 @@ void test_getsockopt() {
 
   close(sockfd);
 }
+#endif // !defined(ORIGIN_TRACKING)
 
 void test_write() {
   int fd = open("/dev/null", O_WRONLY);
@@ -1189,6 +1310,7 @@ void test_write() {
   close(fd);
 }
 
+#if !defined(ORIGIN_TRACKING)
 template <class T>
 void test_sprintf_chunk(const char* expected, const char* format, T arg) {
   char buf[512];
@@ -1316,22 +1438,32 @@ void test_snprintf() {
   ASSERT_READ_LABEL(buf + 17, 2, 0);
   ASSERT_LABEL(r, 0);
 }
+#endif // !defined(ORIGIN_TRACKING)
+
+// Tested by a seperate source file.  This empty function is here to appease the
+// check-wrappers script.
+void test_fork() {}
 
 int main(void) {
 #ifdef FAST_16_LABELS
   i_label = 1;
   j_label = 2;
   k_label = 4;
+  m_label = 8;
+  n_label = 16;
 #else
   i_label = dfsan_create_label("i", 0);
   j_label = dfsan_create_label("j", 0);
   k_label = dfsan_create_label("k", 0);
+  m_label = dfsan_create_label("m", 0);
+  n_label = dfsan_create_label("n", 0);
 #endif
   i_j_label = dfsan_union(i_label, j_label);
   assert(i_j_label != i_label);
   assert(i_j_label != j_label);
   assert(i_j_label != k_label);
 
+#if !defined(ORIGIN_TRACKING)
   test__dl_get_tls_static_info();
   test_bcmp();
   test_calloc();
@@ -1363,17 +1495,21 @@ int main(void) {
   test_nanosleep();
   test_poll();
   test_pread();
+#endif // !defined(ORIGIN_TRACKING)
   test_pthread_create();
   test_pthread_join();
+#if !defined(ORIGIN_TRACKING)
   test_read();
   test_recvmmsg();
   test_recvmsg();
   test_sched_getaffinity();
   test_select();
+#endif // !defined(ORIGIN_TRACKING)
   test_sigaction();
   test_signal();
   test_sigaltstack();
   test_sigemptyset();
+#if !defined(ORIGIN_TRACKING)
   test_snprintf();
   test_socketpair();
   test_sprintf();
@@ -1384,7 +1520,9 @@ int main(void) {
   test_strcat();
   test_strcpy();
   test_strdup();
+#endif // !defined(ORIGIN_TRACKING)
   test_strlen();
+#if !defined(ORIGIN_TRACKING)
   test_strncasecmp();
   test_strncmp();
   test_strncpy();
@@ -1397,5 +1535,7 @@ int main(void) {
   test_strtoul();
   test_strtoull();
   test_time();
+#endif // !defined(ORIGIN_TRACKING)
   test_write();
+  test_fork();
 }

diff  --git a/compiler-rt/test/dfsan/fork.cpp b/compiler-rt/test/dfsan/fork.cpp
new file mode 100644
index 000000000000..cd9b641eefc3
--- /dev/null
+++ b/compiler-rt/test/dfsan/fork.cpp
@@ -0,0 +1,107 @@
+// Test that chained origins are fork-safe.
+// Run a number of threads that create new chained origins, then fork
+// and verify that origin reads do not deadlock in the child process.
+//
+// RUN: %clangxx_dfsan -mllvm -dfsan-fast-16-labels=true %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+//
+// RUN: %clangxx_dfsan -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t
+// RUN: DFSAN_OPTIONS=store_context_size=1000,origin_history_size=0,origin_history_per_stack_limit=0 %run %t 2>&1 | FileCheck %s
+//
+// REQUIRES: x86_64-target-arch
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <sanitizer/dfsan_interface.h>
+
+int done;
+
+void copy_labels_thread2() {
+  volatile int x = 0;
+  volatile int v = 0;
+  dfsan_set_label(8, (void *)&x, sizeof(x));
+  while (true) {
+    v = x;
+    x = v;
+    if (__atomic_load_n(&done, __ATOMIC_RELAXED))
+      return;
+  }
+}
+
+void copy_labels_thread1(int level) {
+  if (!level)
+    copy_labels_thread2();
+  else
+    copy_labels_thread1(level - 1);
+}
+
+void *copy_labels_thread(void *id) {
+  copy_labels_thread1((long)id);
+  return 0;
+}
+
+// Run through stackdepot in the child process.
+// If any of the hash table cells are locked, this may deadlock.
+void child() {
+  volatile int x = 0;
+  volatile int v = 0;
+  dfsan_set_label(16, (void *)&x, sizeof(x));
+  for (int i = 0; i < 10000; ++i) {
+    v = x;
+    x = v;
+  }
+  write(2, "done\n", 5);
+}
+
+void test() {
+  const int kThreads = 10;
+  pthread_t t[kThreads];
+  for (int i = 0; i < kThreads; ++i)
+    pthread_create(&t[i], NULL, copy_labels_thread, (void *)(long)i);
+  usleep(100000);
+  pid_t pid = fork();
+  if (pid) {
+    // parent
+    __atomic_store_n(&done, 1, __ATOMIC_RELAXED);
+    pid_t p;
+    while ((p = wait(NULL)) == -1) {
+    }
+  } else {
+    // child
+    child();
+  }
+}
+
+int main() {
+  const int kChildren = 20;
+  for (int i = 0; i < kChildren; ++i) {
+    pid_t pid = fork();
+    assert(dfsan_get_label(pid) == 0);
+    if (pid) {
+      // parent
+    } else {
+      test();
+      exit(0);
+    }
+  }
+
+  for (int i = 0; i < kChildren; ++i) {
+    pid_t p;
+    while ((p = wait(NULL)) == -1) {
+    }
+  }
+
+  return 0;
+}
+
+// Expect 20 (== kChildren) "done" messages.
+// CHECK-COUNT-20: done

diff  --git a/compiler-rt/test/dfsan/origin_with_sigactions.c b/compiler-rt/test/dfsan/origin_with_sigactions.c
new file mode 100644
index 000000000000..3f7986dd540e
--- /dev/null
+++ b/compiler-rt/test/dfsan/origin_with_sigactions.c
@@ -0,0 +1,79 @@
+// Check that stores in signal handlers are not recorded in origin history.
+//
+// Origin tracking uses ChainedOriginDepot that is not async signal safe, so we
+// do not track origins inside signal handlers.
+//
+// RUN: %clang_dfsan -gmlt -DUSE_SIGNAL_ACTION -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \
+// RUN:      %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+//
+// RUN: %clang_dfsan -gmlt -DUSE_SIGNAL_ACTION -mllvm -dfsan-instrument-with-call-threshold=0 -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \
+// RUN:     %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+//
+// RUN: %clang_dfsan -gmlt -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \
+// RUN:     %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+//
+// RUN: %clang_dfsan -gmlt -mllvm -dfsan-instrument-with-call-threshold=0 -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \
+// RUN:     %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+//
+// REQUIRES: x86_64-target-arch
+
+#include <sanitizer/dfsan_interface.h>
+
+#include <assert.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+int x, y, u;
+
+void CopyXtoYtoU() {
+  y = x;
+  memcpy(&u, &y, sizeof(int));
+}
+
+void SignalHandler(int signo) {
+  CopyXtoYtoU();
+}
+
+void SignalAction(int signo, siginfo_t *si, void *uc) {
+  CopyXtoYtoU();
+}
+
+int main(int argc, char *argv[]) {
+  int z = 1;
+  dfsan_set_label(8, &z, sizeof(z));
+  x = z;
+
+  struct sigaction psa = {};
+#ifdef USE_SIGNAL_ACTION
+  psa.sa_flags = SA_SIGINFO;
+  psa.sa_sigaction = SignalAction;
+#else
+  psa.sa_flags = 0;
+  psa.sa_handler = SignalHandler;
+#endif
+  sigaction(SIGHUP, &psa, NULL);
+  kill(getpid(), SIGHUP);
+  signal(SIGHUP, SIG_DFL);
+
+  assert(x == 1);
+  assert(y == 1);
+  assert(u == 1);
+
+  dfsan_print_origin_trace(&u, NULL);
+  return 0;
+}
+
+// CHECK: Taint value 0x8 {{.*}} origin tracking ()
+// CHECK: Origin value: {{.*}}, Taint value was stored to memory at
+// CHECK-NOT: {{.*}} in dfs$CopyXtoYtoU {{.*}}origin_with_sigactions.c{{.*}}
+
+// CHECK: #0 {{.*}} in main {{.*}}origin_with_sigactions.c:[[@LINE-26]]
+
+// CHECK: Origin value: {{.*}}, Taint value was created at
+// CHECK: #0 {{.*}} in main {{.*}}origin_with_sigactions.c:[[@LINE-30]]

diff  --git a/compiler-rt/test/dfsan/origin_with_signals.cpp b/compiler-rt/test/dfsan/origin_with_signals.cpp
new file mode 100644
index 000000000000..d4885563a447
--- /dev/null
+++ b/compiler-rt/test/dfsan/origin_with_signals.cpp
@@ -0,0 +1,50 @@
+// Check that stores in signal handlers are not recorded in origin history.
+//
+// Origin tracking uses ChainedOriginDepot that is not async signal safe, so we
+// do not track origins inside signal handlers.
+//
+// RUN: %clangxx_dfsan -gmlt -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \
+// RUN:     %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+//
+// RUN: %clangxx_dfsan -gmlt -mllvm -dfsan-instrument-with-call-threshold=0 -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \
+// RUN:     %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+//
+// REQUIRES: x86_64-target-arch
+
+#include <sanitizer/dfsan_interface.h>
+
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+int x, y, u;
+
+void SignalHandler(int signo) {
+  y = x;
+  memcpy(&u, &y, sizeof(int));
+}
+
+int main(int argc, char *argv[]) {
+  int z = 0;
+  dfsan_set_label(8, &z, sizeof(z));
+  x = z;
+
+  signal(SIGHUP, SignalHandler);
+  kill(getpid(), SIGHUP);
+  signal(SIGHUP, SIG_DFL);
+
+  dfsan_print_origin_trace(&u, nullptr);
+  return 0;
+}
+
+// CHECK: Taint value 0x8 {{.*}} origin tracking ()
+// CHECK: Origin value: {{.*}}, Taint value was stored to memory at
+// CHECK-NOT: {{.*}} in dfs$SignalHandler {{.*}}origin_with_signals.cpp{{.*}}
+
+// CHECK: #0 {{.*}} in main {{.*}}origin_with_signals.cpp:[[@LINE-14]]
+
+// CHECK: Origin value: {{.*}}, Taint value was created at
+// CHECK: #0 {{.*}} in main {{.*}}origin_with_signals.cpp:[[@LINE-18]]

diff  --git a/compiler-rt/test/dfsan/pthread.c b/compiler-rt/test/dfsan/pthread.c
index 6824cb32c003..75bc4720cea8 100644
--- a/compiler-rt/test/dfsan/pthread.c
+++ b/compiler-rt/test/dfsan/pthread.c
@@ -1,29 +1,53 @@
 // RUN: %clang_dfsan -mllvm -dfsan-fast-16-labels=true %s -o %t && %run %t
+//
+// RUN: %clang_dfsan -gmlt -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \
+// RUN:     %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+//
+// RUN: %clang_dfsan -gmlt -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true -mllvm -dfsan-instrument-with-call-threshold=0 %s -o %t && \
+// RUN:     %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+//
+// REQUIRES: x86_64-target-arch
 
 #include <sanitizer/dfsan_interface.h>
 
 #include <assert.h>
 #include <pthread.h>
+#include <string.h>
 
-int volatile x;
-int __thread y;
+const int kNumThreads = 24;
+int x = 0;
+int __thread y, z;
 
 static void *ThreadFn(void *a) {
   y = x;
   assert(dfsan_get_label(y) == 8);
+  memcpy(&z, &y, sizeof(y));
+  if ((int)a == 7)
+    dfsan_print_origin_trace(&z, NULL);
   return 0;
 }
 
 int main(void) {
   dfsan_set_label(8, &x, sizeof(x));
 
-  const int kNumThreads = 24;
   pthread_t t[kNumThreads];
-  for (size_t i = 0; i < kNumThreads; ++i) {
+  for (size_t i = 0; i < kNumThreads; ++i)
     pthread_create(&t[i], 0, ThreadFn, (void *)i);
-  }
-  for (size_t i = 0; i < kNumThreads; ++i) {
+
+  for (size_t i = 0; i < kNumThreads; ++i)
     pthread_join(t[i], 0);
-  }
+
   return 0;
 }
+
+// CHECK: Taint value 0x8 {{.*}} origin tracking ()
+// CHECK: Origin value: {{.*}}, Taint value was stored to memory at
+// CHECK: #0 {{.*}} in dfs$ThreadFn {{.*}}pthread.c:[[@LINE-21]]
+
+// CHECK: Origin value: {{.*}}, Taint value was stored to memory at
+// CHECK: #0 {{.*}} in dfs$ThreadFn {{.*}}pthread.c:[[@LINE-26]]
+
+// CHECK: Origin value: {{.*}}, Taint value was created at
+// CHECK: #0 {{.*}} in main {{.*}}pthread.c:[[@LINE-20]]

diff  --git a/compiler-rt/test/dfsan/sigaction_stress_test.c b/compiler-rt/test/dfsan/sigaction_stress_test.c
index 0748d20972a3..edb45fa5caf4 100644
--- a/compiler-rt/test/dfsan/sigaction_stress_test.c
+++ b/compiler-rt/test/dfsan/sigaction_stress_test.c
@@ -1,6 +1,10 @@
-// RUN: %clangxx_dfsan -mllvm -dfsan-fast-16-labels=true -O0 %s -o %t && %run %t
+// RUN: %clangxx_dfsan -mllvm -dfsan-fast-16-labels=true %s -o %t && %run %t
+// RUN: %clangxx_dfsan -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && %run %t
+// RUN: %clangxx_dfsan -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true -mllvm -dfsan-instrument-with-call-threshold=0 %s -o %t && %run %t
 //
 // Test that the state of shadows from a sigaction handler are consistent.
+//
+// REQUIRES: x86_64-target-arch
 
 #include <signal.h>
 #include <stdarg.h>
@@ -10,7 +14,7 @@
 #include <stdio.h>
 
 const int kSigCnt = 200;
-int x;
+int x = 0;
 
 __attribute__((noinline))
 int f(int a) {


        


More information about the llvm-commits mailing list