[llvm-branch-commits] [clang] [compiler-rt] [TySan] A Type Sanitizer (Runtime Library) (PR #76261)

Florian Hahn via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Jun 27 09:10:18 PDT 2024


https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/76261

>From 733b3ed3f7441453889157834e0a5b6c288bf976 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 27 Jun 2024 15:48:05 +0100
Subject: [PATCH] [tysan] Add runtime support

---
 clang/runtime/CMakeLists.txt                  |   2 +-
 .../cmake/Modules/AllSupportedArchDefs.cmake  |   1 +
 compiler-rt/cmake/config-ix.cmake             |  14 +-
 compiler-rt/lib/tysan/CMakeLists.txt          |  64 ++++
 compiler-rt/lib/tysan/lit.cfg                 |  35 ++
 compiler-rt/lib/tysan/lit.site.cfg.in         |  12 +
 compiler-rt/lib/tysan/tysan.cpp               | 339 ++++++++++++++++++
 compiler-rt/lib/tysan/tysan.h                 |  79 ++++
 compiler-rt/lib/tysan/tysan.syms.extra        |   2 +
 compiler-rt/lib/tysan/tysan_flags.inc         |  17 +
 compiler-rt/lib/tysan/tysan_interceptors.cpp  | 250 +++++++++++++
 compiler-rt/lib/tysan/tysan_platform.h        |  93 +++++
 compiler-rt/test/tysan/CMakeLists.txt         |  32 ++
 compiler-rt/test/tysan/anon-ns.cpp            |  41 +++
 compiler-rt/test/tysan/anon-same-struct.c     |  26 ++
 compiler-rt/test/tysan/anon-struct.c          |  27 ++
 compiler-rt/test/tysan/basic.c                |  65 ++++
 compiler-rt/test/tysan/char-memcpy.c          |  45 +++
 compiler-rt/test/tysan/global.c               |  31 ++
 compiler-rt/test/tysan/int-long.c             |  21 ++
 compiler-rt/test/tysan/lit.cfg.py             | 139 +++++++
 compiler-rt/test/tysan/lit.site.cfg.py.in     |  17 +
 compiler-rt/test/tysan/ptr-float.c            |  19 +
 ...ruct-offset-multiple-compilation-units.cpp |  51 +++
 compiler-rt/test/tysan/struct-offset.c        |  26 ++
 compiler-rt/test/tysan/struct.c               |  39 ++
 compiler-rt/test/tysan/union-wr-wr.c          |  18 +
 compiler-rt/test/tysan/violation-pr45282.c    |  32 ++
 compiler-rt/test/tysan/violation-pr47137.c    |  40 +++
 compiler-rt/test/tysan/violation-pr51837.c    |  34 ++
 compiler-rt/test/tysan/violation-pr62544.c    |  24 ++
 compiler-rt/test/tysan/violation-pr62828.cpp  |  44 +++
 compiler-rt/test/tysan/violation-pr68655.cpp  |  40 +++
 compiler-rt/test/tysan/violation-pr86685.c    |  29 ++
 34 files changed, 1746 insertions(+), 2 deletions(-)
 create mode 100644 compiler-rt/lib/tysan/CMakeLists.txt
 create mode 100644 compiler-rt/lib/tysan/lit.cfg
 create mode 100644 compiler-rt/lib/tysan/lit.site.cfg.in
 create mode 100644 compiler-rt/lib/tysan/tysan.cpp
 create mode 100644 compiler-rt/lib/tysan/tysan.h
 create mode 100644 compiler-rt/lib/tysan/tysan.syms.extra
 create mode 100644 compiler-rt/lib/tysan/tysan_flags.inc
 create mode 100644 compiler-rt/lib/tysan/tysan_interceptors.cpp
 create mode 100644 compiler-rt/lib/tysan/tysan_platform.h
 create mode 100644 compiler-rt/test/tysan/CMakeLists.txt
 create mode 100644 compiler-rt/test/tysan/anon-ns.cpp
 create mode 100644 compiler-rt/test/tysan/anon-same-struct.c
 create mode 100644 compiler-rt/test/tysan/anon-struct.c
 create mode 100644 compiler-rt/test/tysan/basic.c
 create mode 100644 compiler-rt/test/tysan/char-memcpy.c
 create mode 100644 compiler-rt/test/tysan/global.c
 create mode 100644 compiler-rt/test/tysan/int-long.c
 create mode 100644 compiler-rt/test/tysan/lit.cfg.py
 create mode 100644 compiler-rt/test/tysan/lit.site.cfg.py.in
 create mode 100644 compiler-rt/test/tysan/ptr-float.c
 create mode 100644 compiler-rt/test/tysan/struct-offset-multiple-compilation-units.cpp
 create mode 100644 compiler-rt/test/tysan/struct-offset.c
 create mode 100644 compiler-rt/test/tysan/struct.c
 create mode 100644 compiler-rt/test/tysan/union-wr-wr.c
 create mode 100644 compiler-rt/test/tysan/violation-pr45282.c
 create mode 100644 compiler-rt/test/tysan/violation-pr47137.c
 create mode 100644 compiler-rt/test/tysan/violation-pr51837.c
 create mode 100644 compiler-rt/test/tysan/violation-pr62544.c
 create mode 100644 compiler-rt/test/tysan/violation-pr62828.cpp
 create mode 100644 compiler-rt/test/tysan/violation-pr68655.cpp
 create mode 100644 compiler-rt/test/tysan/violation-pr86685.c

diff --git a/clang/runtime/CMakeLists.txt b/clang/runtime/CMakeLists.txt
index 65fcdc2868f03..ff2605b23d25b 100644
--- a/clang/runtime/CMakeLists.txt
+++ b/clang/runtime/CMakeLists.txt
@@ -122,7 +122,7 @@ if(LLVM_BUILD_EXTERNAL_COMPILER_RT AND EXISTS ${COMPILER_RT_SRC_ROOT}/)
                            COMPONENT compiler-rt)
 
   # Add top-level targets that build specific compiler-rt runtimes.
-  set(COMPILER_RT_RUNTIMES fuzzer asan builtins dfsan lsan msan profile tsan ubsan ubsan-minimal)
+  set(COMPILER_RT_RUNTIMES fuzzer asan builtins dfsan lsan msan profile tsan tysan ubsan ubsan-minimal)
   foreach(runtime ${COMPILER_RT_RUNTIMES})
     get_ext_project_build_command(build_runtime_cmd ${runtime})
     add_custom_target(${runtime}
diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
index ac4a71202384d..4701b58de4bda 100644
--- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
+++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
@@ -70,6 +70,7 @@ set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC32} ${PPC
 set(ALL_CTX_PROFILE_SUPPORTED_ARCH ${X86_64})
 set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64} ${S390X}
     ${LOONGARCH64} ${RISCV64})
+set(ALL_TYSAN_SUPPORTED_ARCH ${X86_64} ${ARM64})
 set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64}
     ${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON}
     ${LOONGARCH64})
diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake
index 75e4d3677703a..ab13d8c036839 100644
--- a/compiler-rt/cmake/config-ix.cmake
+++ b/compiler-rt/cmake/config-ix.cmake
@@ -434,6 +434,7 @@ if(APPLE)
   set(SANITIZER_COMMON_SUPPORTED_OS osx)
   set(PROFILE_SUPPORTED_OS osx)
   set(TSAN_SUPPORTED_OS osx)
+  set(TYSAN_SUPPORTED_OS osx)
   set(XRAY_SUPPORTED_OS osx)
   set(FUZZER_SUPPORTED_OS osx)
   set(ORC_SUPPORTED_OS)
@@ -569,6 +570,7 @@ if(APPLE)
           list(APPEND FUZZER_SUPPORTED_OS ${platform})
           list(APPEND ORC_SUPPORTED_OS ${platform})
           list(APPEND UBSAN_SUPPORTED_OS ${platform})
+          list(APPEND TYSAN_SUPPORTED_OS ${platform})
           list(APPEND LSAN_SUPPORTED_OS ${platform})
           list(APPEND STATS_SUPPORTED_OS ${platform})
         endif()
@@ -624,6 +626,9 @@ if(APPLE)
   list_intersect(CTX_PROFILE_SUPPORTED_ARCH
     ALL_CTX_PROFILE_SUPPORTED_ARCH
     SANITIZER_COMMON_SUPPORTED_ARCH)
+  list_intersect(TYSAN_SUPPORTED_ARCH
+    ALL_TYSAN_SUPPORTED_ARCH
+    SANITIZER_COMMON_SUPPORTED_ARCH)
   list_intersect(TSAN_SUPPORTED_ARCH
     ALL_TSAN_SUPPORTED_ARCH
     SANITIZER_COMMON_SUPPORTED_ARCH)
@@ -716,7 +721,7 @@ if(COMPILER_RT_SUPPORTED_ARCH)
 endif()
 message(STATUS "Compiler-RT supported architectures: ${COMPILER_RT_SUPPORTED_ARCH}")
 
-set(ALL_SANITIZERS asan;dfsan;msan;hwasan;tsan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;nsan;asan_abi)
+set(ALL_SANITIZERS asan;dfsan;msan;hwasan;tsan;tysan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;nsan;asan_abi)
 set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING
     "sanitizers to build if supported on the target (all;${ALL_SANITIZERS})")
 list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}")
@@ -804,6 +809,13 @@ else()
   set(COMPILER_RT_HAS_CTX_PROFILE FALSE)
 endif()
 
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND TYSAN_SUPPORTED_ARCH AND
+        OS_NAME MATCHES "Linux|Darwin")
+  set(COMPILER_RT_HAS_TYSAN TRUE)
+else()
+  set(COMPILER_RT_HAS_TYSAN FALSE)
+endif()
+
 if (COMPILER_RT_HAS_SANITIZER_COMMON AND TSAN_SUPPORTED_ARCH)
   if (OS_NAME MATCHES "Linux|Darwin|FreeBSD|NetBSD")
     set(COMPILER_RT_HAS_TSAN TRUE)
diff --git a/compiler-rt/lib/tysan/CMakeLists.txt b/compiler-rt/lib/tysan/CMakeLists.txt
new file mode 100644
index 0000000000000..859b67928f004
--- /dev/null
+++ b/compiler-rt/lib/tysan/CMakeLists.txt
@@ -0,0 +1,64 @@
+include_directories(..)
+
+# Runtime library sources and build flags.
+set(TYSAN_SOURCES
+  tysan.cpp
+  tysan_interceptors.cpp)
+set(TYSAN_COMMON_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_rtti_flag(OFF TYSAN_COMMON_CFLAGS)
+# Prevent clang from generating libc calls.
+append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding TYSAN_COMMON_CFLAGS)
+
+add_compiler_rt_object_libraries(RTTysan_dynamic
+  OS ${SANITIZER_COMMON_SUPPORTED_OS}
+  ARCHS ${TYSAN_SUPPORTED_ARCH}
+  SOURCES ${TYSAN_SOURCES}
+  ADDITIONAL_HEADERS ${TYSAN_HEADERS}
+  CFLAGS ${TYSAN_DYNAMIC_CFLAGS}
+  DEFS ${TYSAN_DYNAMIC_DEFINITIONS})
+
+
+# Static runtime library.
+add_compiler_rt_component(tysan)
+
+
+if(APPLE)
+  add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS)
+
+  add_compiler_rt_runtime(clang_rt.tysan
+    SHARED
+    OS ${SANITIZER_COMMON_SUPPORTED_OS}
+    ARCHS ${TYSAN_SUPPORTED_ARCH}
+    OBJECT_LIBS RTTysan_dynamic
+                RTInterception
+                RTSanitizerCommon
+                RTSanitizerCommonLibc
+                RTSanitizerCommonSymbolizer
+    CFLAGS ${TYSAN_DYNAMIC_CFLAGS}
+    LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS}
+    DEFS ${TYSAN_DYNAMIC_DEFINITIONS}
+    PARENT_TARGET tysan)
+
+  add_compiler_rt_runtime(clang_rt.tysan_static
+    STATIC
+    ARCHS ${TYSAN_SUPPORTED_ARCH}
+    OBJECT_LIBS RTTysan_static
+    CFLAGS ${TYSAN_CFLAGS}
+    DEFS ${TYSAN_COMMON_DEFINITIONS}
+    PARENT_TARGET tysan)
+else()
+  foreach(arch ${TYSAN_SUPPORTED_ARCH})
+    set(TYSAN_CFLAGS ${TYSAN_COMMON_CFLAGS})
+    append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE TYSAN_CFLAGS)
+    add_compiler_rt_runtime(clang_rt.tysan
+      STATIC
+      ARCHS ${arch}
+      SOURCES ${TYSAN_SOURCES}
+              $<TARGET_OBJECTS:RTInterception.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
+      CFLAGS ${TYSAN_CFLAGS}
+      PARENT_TARGET tysan)
+  endforeach()
+endif()
diff --git a/compiler-rt/lib/tysan/lit.cfg b/compiler-rt/lib/tysan/lit.cfg
new file mode 100644
index 0000000000000..bd2bbe855529a
--- /dev/null
+++ b/compiler-rt/lib/tysan/lit.cfg
@@ -0,0 +1,35 @@
+# -*- Python -*-
+
+import os
+
+# Setup config name.
+config.name = 'TypeSanitizer' + getattr(config, 'name_suffix', 'default')
+
+# Setup source root.
+config.test_source_root = os.path.dirname(__file__)
+
+# Setup default compiler flags used with -fsanitize=type option.
+clang_tysan_cflags = (["-fsanitize=type",
+                      "-mno-omit-leaf-frame-pointer",
+                      "-fno-omit-frame-pointer",
+                      "-fno-optimize-sibling-calls"] +
+                      [config.target_cflags] +
+                      config.debug_info_flags)
+clang_tysan_cxxflags = config.cxx_mode_flags + clang_tysan_cflags
+
+def build_invocation(compile_flags):
+  return " " + " ".join([config.clang] + compile_flags) + " "
+
+config.substitutions.append( ("%clang_tysan ", build_invocation(clang_tysan_cflags)) )
+config.substitutions.append( ("%clangxx_tysan ", build_invocation(clang_tysan_cxxflags)) )
+
+# Default test suffixes.
+config.suffixes = ['.c', '.cc', '.cpp']
+
+# TypeSanitizer tests are currently supported on Linux only.
+if config.host_os not in ['Linux']:
+  config.unsupported = True
+
+if config.target_arch != 'aarch64':
+  config.available_features.add('stable-runtime')
+
diff --git a/compiler-rt/lib/tysan/lit.site.cfg.in b/compiler-rt/lib/tysan/lit.site.cfg.in
new file mode 100644
index 0000000000000..673d04e514379
--- /dev/null
+++ b/compiler-rt/lib/tysan/lit.site.cfg.in
@@ -0,0 +1,12 @@
+ at LIT_SITE_CFG_IN_HEADER@
+
+# Tool-specific config options.
+config.name_suffix = "@TYSAN_TEST_CONFIG_SUFFIX@"
+config.target_cflags = "@TYSAN_TEST_TARGET_CFLAGS@"
+config.target_arch = "@TYSAN_TEST_TARGET_ARCH@"
+
+# Load common config for all compiler-rt lit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
+
+# Load tool-specific config that would do the real work.
+lit_config.load_config(config, "@TYSAN_LIT_SOURCE_DIR@/lit.cfg")
diff --git a/compiler-rt/lib/tysan/tysan.cpp b/compiler-rt/lib/tysan/tysan.cpp
new file mode 100644
index 0000000000000..f627851d049e6
--- /dev/null
+++ b/compiler-rt/lib/tysan/tysan.cpp
@@ -0,0 +1,339 @@
+//===-- tysan.cpp ---------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of TypeSanitizer.
+//
+// TypeSanitizer runtime.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_report_decorator.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+#include "tysan/tysan.h"
+
+using namespace __sanitizer;
+using namespace __tysan;
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
+tysan_set_type_unknown(const void *addr, uptr size) {
+  if (tysan_inited)
+    internal_memset(shadow_for(addr), 0, size * sizeof(uptr));
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
+tysan_copy_types(const void *daddr, const void *saddr, uptr size) {
+  if (tysan_inited)
+    internal_memmove(shadow_for(daddr), shadow_for(saddr), size * sizeof(uptr));
+}
+
+static const char *getDisplayName(const char *Name) {
+  if (Name[0] == '\0')
+    return "<anonymous type>";
+
+  // Clang generates tags for C++ types that demangle as typeinfo. Remove the
+  // prefix from the generated string.
+  const char TIPrefix[] = "typeinfo name for ";
+
+  const char *DName = Symbolizer::GetOrInit()->Demangle(Name);
+  if (!internal_strncmp(DName, TIPrefix, sizeof(TIPrefix) - 1))
+    DName += sizeof(TIPrefix) - 1;
+
+  return DName;
+}
+
+static void printTDName(tysan_type_descriptor *td) {
+  if (((sptr)td) <= 0) {
+    Printf("<unknown type>");
+    return;
+  }
+
+  switch (td->Tag) {
+  default:
+    DCHECK(0);
+    break;
+  case TYSAN_MEMBER_TD:
+    printTDName(td->Member.Access);
+    if (td->Member.Access != td->Member.Base) {
+      Printf(" (in ");
+      printTDName(td->Member.Base);
+      Printf(" at offset %zu)", td->Member.Offset);
+    }
+    break;
+  case TYSAN_STRUCT_TD:
+    Printf("%s", getDisplayName(
+                     (char *)(td->Struct.Members + td->Struct.MemberCount)));
+    break;
+  }
+}
+
+static tysan_type_descriptor *getRootTD(tysan_type_descriptor *TD) {
+  tysan_type_descriptor *RootTD = TD;
+
+  do {
+    RootTD = TD;
+
+    if (TD->Tag == TYSAN_STRUCT_TD) {
+      if (TD->Struct.MemberCount > 0)
+        TD = TD->Struct.Members[0].Type;
+      else
+        TD = nullptr;
+    } else if (TD->Tag == TYSAN_MEMBER_TD) {
+      TD = TD->Member.Access;
+    } else {
+      DCHECK(0);
+      break;
+    }
+  } while (TD);
+
+  return RootTD;
+}
+
+static bool isAliasingLegalUp(tysan_type_descriptor *TDA,
+                              tysan_type_descriptor *TDB) {
+  // Walk up the tree starting with TDA to see if we reach TDB.
+  uptr OffsetA = 0, OffsetB = 0;
+  if (TDB->Tag == TYSAN_MEMBER_TD) {
+    OffsetB = TDB->Member.Offset;
+    TDB = TDB->Member.Base;
+  }
+
+  if (TDA->Tag == TYSAN_MEMBER_TD) {
+    OffsetA = TDA->Member.Offset;
+    TDA = TDA->Member.Base;
+  }
+
+  do {
+    if (TDA == TDB)
+      return OffsetA == OffsetB;
+
+    if (TDA->Tag == TYSAN_STRUCT_TD) {
+      // Reached root type descriptor.
+      if (!TDA->Struct.MemberCount)
+        break;
+
+      uptr Idx = 0;
+      for (; Idx < TDA->Struct.MemberCount - 1; ++Idx) {
+        if (TDA->Struct.Members[Idx].Offset >= OffsetA)
+          break;
+      }
+
+      OffsetA -= TDA->Struct.Members[Idx].Offset;
+      TDA = TDA->Struct.Members[Idx].Type;
+    } else {
+      DCHECK(0);
+      break;
+    }
+  } while (TDA);
+
+  return false;
+}
+
+static bool isAliasingLegal(tysan_type_descriptor *TDA,
+                            tysan_type_descriptor *TDB) {
+  if (TDA == TDB || !TDB || !TDA)
+    return true;
+
+  // Aliasing is legal is the two types have different root nodes.
+  if (getRootTD(TDA) != getRootTD(TDB))
+    return true;
+
+  return isAliasingLegalUp(TDA, TDB) || isAliasingLegalUp(TDB, TDA);
+}
+
+namespace __tysan {
+class Decorator : public __sanitizer::SanitizerCommonDecorator {
+public:
+  Decorator() : SanitizerCommonDecorator() {}
+  const char *Warning() { return Red(); }
+  const char *Name() { return Green(); }
+  const char *End() { return Default(); }
+};
+} // namespace __tysan
+
+ALWAYS_INLINE
+static void reportError(void *Addr, int Size, tysan_type_descriptor *TD,
+                        tysan_type_descriptor *OldTD, const char *AccessStr,
+                        const char *DescStr, int Offset, uptr pc, uptr bp,
+                        uptr sp) {
+  Decorator d;
+  Printf("%s", d.Warning());
+  Report("ERROR: TypeSanitizer: type-aliasing-violation on address %p"
+         " (pc %p bp %p sp %p tid %llu)\n",
+         Addr, (void *)pc, (void *)bp, (void *)sp, GetTid());
+  Printf("%s", d.End());
+  Printf("%s of size %d at %p with type ", AccessStr, Size, Addr);
+
+  Printf("%s", d.Name());
+  printTDName(TD);
+  Printf("%s", d.End());
+
+  Printf(" %s of type ", DescStr);
+
+  Printf("%s", d.Name());
+  printTDName(OldTD);
+  Printf("%s", d.End());
+
+  if (Offset != 0)
+    Printf(" that starts at offset %d\n", Offset);
+  else
+    Printf("\n");
+
+  if (pc) {
+
+    bool request_fast = StackTrace::WillUseFastUnwind(true);
+    BufferedStackTrace ST;
+    ST.Unwind(kStackTraceMax, pc, bp, 0, 0, 0, request_fast);
+    ST.Print();
+  } else {
+    Printf("\n");
+  }
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
+__tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) {
+  GET_CALLER_PC_BP_SP;
+
+  bool IsRead = flags & 1;
+  bool IsWrite = flags & 2;
+  const char *AccessStr;
+  if (IsRead && !IsWrite)
+    AccessStr = "READ";
+  else if (!IsRead && IsWrite)
+    AccessStr = "WRITE";
+  else
+    AccessStr = "ATOMIC UPDATE";
+
+  tysan_type_descriptor **OldTDPtr = shadow_for(addr);
+  tysan_type_descriptor *OldTD = *OldTDPtr;
+  if (((sptr)OldTD) < 0) {
+    int i = -((sptr)OldTD);
+    OldTDPtr -= i;
+    OldTD = *OldTDPtr;
+
+    if (!isAliasingLegal(td, OldTD))
+      reportError(addr, size, td, OldTD, AccessStr,
+                  "accesses part of an existing object", -i, pc, bp, sp);
+
+    return;
+  }
+
+  if (!isAliasingLegal(td, OldTD)) {
+    reportError(addr, size, td, OldTD, AccessStr, "accesses an existing object",
+                0, pc, bp, sp);
+    return;
+  }
+
+  // These types are allowed to alias (or the stored type is unknown), report
+  // an error if we find an interior type.
+
+  for (int i = 0; i < size; ++i) {
+    OldTDPtr = shadow_for((void *)(((uptr)addr) + i));
+    OldTD = *OldTDPtr;
+    if (((sptr)OldTD) >= 0 && !isAliasingLegal(td, OldTD))
+      reportError(addr, size, td, OldTD, AccessStr,
+                  "partially accesses an object", i, pc, bp, sp);
+  }
+}
+
+Flags __tysan::flags_data;
+
+SANITIZER_INTERFACE_ATTRIBUTE uptr __tysan_shadow_memory_address;
+SANITIZER_INTERFACE_ATTRIBUTE uptr __tysan_app_memory_mask;
+
+#ifdef TYSAN_RUNTIME_VMA
+// Runtime detected VMA size.
+int __tysan::vmaSize;
+#endif
+
+void Flags::SetDefaults() {
+#define TYSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
+#include "tysan_flags.inc"
+#undef TYSAN_FLAG
+}
+
+static void RegisterTySanFlags(FlagParser *parser, Flags *f) {
+#define TYSAN_FLAG(Type, Name, DefaultValue, Description)                      \
+  RegisterFlag(parser, #Name, Description, &f->Name);
+#include "tysan_flags.inc"
+#undef TYSAN_FLAG
+}
+
+static void InitializeFlags() {
+  SetCommonFlagsDefaults();
+  {
+    CommonFlags cf;
+    cf.CopyFrom(*common_flags());
+    cf.external_symbolizer_path = GetEnv("TYSAN_SYMBOLIZER_PATH");
+    OverrideCommonFlags(cf);
+  }
+
+  flags().SetDefaults();
+
+  FlagParser parser;
+  RegisterCommonFlags(&parser);
+  RegisterTySanFlags(&parser, &flags());
+  parser.ParseString(GetEnv("TYSAN_OPTIONS"));
+  InitializeCommonFlags();
+  if (Verbosity())
+    ReportUnrecognizedFlags();
+  if (common_flags()->help)
+    parser.PrintFlagDescriptions();
+}
+
+static void TySanInitializePlatformEarly() {
+  AvoidCVE_2016_2143();
+#ifdef TYSAN_RUNTIME_VMA
+  vmaSize = (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);
+#if defined(__aarch64__) && !SANITIZER_APPLE
+  if (vmaSize != 39 && vmaSize != 42 && vmaSize != 48) {
+    Printf("FATAL: TypeSanitizer: unsupported VMA range\n");
+    Printf("FATAL: Found %d - Supported 39, 42 and 48\n", vmaSize);
+    Die();
+  }
+#endif
+#endif
+
+  __sanitizer::InitializePlatformEarly();
+
+  __tysan_shadow_memory_address = ShadowAddr();
+  __tysan_app_memory_mask = AppMask();
+}
+
+namespace __tysan {
+bool tysan_inited = false;
+bool tysan_init_is_running;
+} // namespace __tysan
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __tysan_init() {
+  CHECK(!tysan_init_is_running);
+  if (tysan_inited)
+    return;
+  tysan_init_is_running = true;
+
+  InitializeFlags();
+  TySanInitializePlatformEarly();
+
+  InitializeInterceptors();
+
+  if (!MmapFixedNoReserve(ShadowAddr(), AppAddr() - ShadowAddr()))
+    Die();
+
+  tysan_init_is_running = false;
+  tysan_inited = true;
+}
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+__attribute__((section(".preinit_array"),
+               used)) static void (*tysan_init_ptr)() = __tysan_init;
+#endif
diff --git a/compiler-rt/lib/tysan/tysan.h b/compiler-rt/lib/tysan/tysan.h
new file mode 100644
index 0000000000000..ec6f9587e9ce5
--- /dev/null
+++ b/compiler-rt/lib/tysan/tysan.h
@@ -0,0 +1,79 @@
+//===-- tysan.h -------------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of TypeSanitizer.
+//
+// Private TySan header.
+//===----------------------------------------------------------------------===//
+
+#ifndef TYSAN_H
+#define TYSAN_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+using __sanitizer::sptr;
+using __sanitizer::u16;
+using __sanitizer::uptr;
+
+#include "tysan_platform.h"
+
+extern "C" {
+void tysan_set_type_unknown(const void *addr, uptr size);
+void tysan_copy_types(const void *daddr, const void *saddr, uptr size);
+}
+
+namespace __tysan {
+extern bool tysan_inited;
+extern bool tysan_init_is_running;
+
+void InitializeInterceptors();
+
+enum { TYSAN_MEMBER_TD = 1, TYSAN_STRUCT_TD = 2 };
+
+struct tysan_member_type_descriptor {
+  struct tysan_type_descriptor *Base;
+  struct tysan_type_descriptor *Access;
+  uptr Offset;
+};
+
+struct tysan_struct_type_descriptor {
+  uptr MemberCount;
+  struct {
+    struct tysan_type_descriptor *Type;
+    uptr Offset;
+  } Members[1]; // Tail allocated.
+  // char Name[]; // Tail allocated.
+};
+
+struct tysan_type_descriptor {
+  uptr Tag;
+  union {
+    tysan_member_type_descriptor Member;
+    tysan_struct_type_descriptor Struct;
+  };
+};
+
+inline tysan_type_descriptor **shadow_for(const void *ptr) {
+  return (tysan_type_descriptor **)((((uptr)ptr) & AppMask()) * sizeof(ptr) +
+                                    ShadowAddr());
+}
+
+struct Flags {
+#define TYSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
+#include "tysan_flags.inc"
+#undef TYSAN_FLAG
+
+  void SetDefaults();
+};
+
+extern Flags flags_data;
+inline Flags &flags() { return flags_data; }
+
+} // namespace __tysan
+
+#endif // TYSAN_H
diff --git a/compiler-rt/lib/tysan/tysan.syms.extra b/compiler-rt/lib/tysan/tysan.syms.extra
new file mode 100644
index 0000000000000..04e7854316199
--- /dev/null
+++ b/compiler-rt/lib/tysan/tysan.syms.extra
@@ -0,0 +1,2 @@
+tysan_*
+__tysan_*
diff --git a/compiler-rt/lib/tysan/tysan_flags.inc b/compiler-rt/lib/tysan/tysan_flags.inc
new file mode 100644
index 0000000000000..98b6591f844ef
--- /dev/null
+++ b/compiler-rt/lib/tysan/tysan_flags.inc
@@ -0,0 +1,17 @@
+//===-- tysan_flags.inc ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// TySan runtime flags.
+//
+//===----------------------------------------------------------------------===//
+#ifndef TYSAN_FLAG
+#error "Define TYSAN_FLAG prior to including this file!"
+#endif
+
+// TYSAN_FLAG(Type, Name, DefaultValue, Description)
+// See COMMON_FLAG in sanitizer_flags.inc for more details.
diff --git a/compiler-rt/lib/tysan/tysan_interceptors.cpp b/compiler-rt/lib/tysan/tysan_interceptors.cpp
new file mode 100644
index 0000000000000..5fc6f24412272
--- /dev/null
+++ b/compiler-rt/lib/tysan/tysan_interceptors.cpp
@@ -0,0 +1,250 @@
+//===-- tysan_interceptors.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of TypeSanitizer.
+//
+// Interceptors for standard library functions.
+//===----------------------------------------------------------------------===//
+
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "tysan/tysan.h"
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#define TYSAN_INTERCEPT___STRDUP 1
+#else
+#define TYSAN_INTERCEPT___STRDUP 0
+#endif
+
+#if SANITIZER_LINUX
+extern "C" int mallopt(int param, int value);
+#endif
+
+using namespace __sanitizer;
+using namespace __tysan;
+
+static const uptr early_alloc_buf_size = 16384;
+static uptr allocated_bytes;
+static char early_alloc_buf[early_alloc_buf_size];
+
+static bool isInEarlyAllocBuf(const void *ptr) {
+  return ((uptr)ptr >= (uptr)early_alloc_buf &&
+          ((uptr)ptr - (uptr)early_alloc_buf) < sizeof(early_alloc_buf));
+}
+
+// Handle allocation requests early (before all interceptors are setup). dlsym,
+// for example, calls calloc.
+static void *handleEarlyAlloc(uptr size) {
+  void *mem = (void *)&early_alloc_buf[allocated_bytes];
+  allocated_bytes += size;
+  CHECK_LT(allocated_bytes, early_alloc_buf_size);
+  return mem;
+}
+
+INTERCEPTOR(void *, memset, void *dst, int v, uptr size) {
+  if (!tysan_inited && REAL(memset) == nullptr)
+    return internal_memset(dst, v, size);
+
+  void *res = REAL(memset)(dst, v, size);
+  tysan_set_type_unknown(dst, size);
+  return res;
+}
+
+INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) {
+  if (!tysan_inited && REAL(memmove) == nullptr)
+    return internal_memmove(dst, src, size);
+
+  void *res = REAL(memmove)(dst, src, size);
+  tysan_copy_types(dst, src, size);
+  return res;
+}
+
+INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) {
+  if (!tysan_inited && REAL(memcpy) == nullptr) {
+    // memmove is used here because on some platforms this will also
+    // intercept the memmove implementation.
+    return internal_memmove(dst, src, size);
+  }
+
+  void *res = REAL(memcpy)(dst, src, size);
+  tysan_copy_types(dst, src, size);
+  return res;
+}
+
+INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags,
+            int fd, OFF_T offset) {
+  void *res = REAL(mmap)(addr, length, prot, flags, fd, offset);
+  if (res != (void *)-1)
+    tysan_set_type_unknown(res, RoundUpTo(length, GetPageSize()));
+  return res;
+}
+
+#if !SANITIZER_APPLE
+INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags,
+            int fd, OFF64_T offset) {
+  void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset);
+  if (res != (void *)-1)
+    tysan_set_type_unknown(res, RoundUpTo(length, GetPageSize()));
+  return res;
+}
+#endif
+
+INTERCEPTOR(char *, strdup, const char *s) {
+  char *res = REAL(strdup)(s);
+  if (res)
+    tysan_copy_types(res, const_cast<char *>(s), internal_strlen(s));
+  return res;
+}
+
+#if TYSAN_INTERCEPT___STRDUP
+INTERCEPTOR(char *, __strdup, const char *s) {
+  char *res = REAL(__strdup)(s);
+  if (res)
+    tysan_copy_types(res, const_cast<char *>(s), internal_strlen(s));
+  return res;
+}
+#endif // TYSAN_INTERCEPT___STRDUP
+
+INTERCEPTOR(void *, malloc, uptr size) {
+  if (tysan_init_is_running && REAL(malloc) == nullptr)
+    return handleEarlyAlloc(size);
+
+  void *res = REAL(malloc)(size);
+  if (res)
+    tysan_set_type_unknown(res, size);
+  return res;
+}
+
+INTERCEPTOR(void *, realloc, void *ptr, uptr size) {
+  void *res = REAL(realloc)(ptr, size);
+  // We might want to copy the types from the original allocation (although
+  // that would require that we knew its size).
+  if (res)
+    tysan_set_type_unknown(res, size);
+  return res;
+}
+
+INTERCEPTOR(void *, calloc, uptr nmemb, uptr size) {
+  if (tysan_init_is_running && REAL(calloc) == nullptr)
+    return handleEarlyAlloc(nmemb * size);
+
+  void *res = REAL(calloc)(nmemb, size);
+  if (res)
+    tysan_set_type_unknown(res, nmemb * size);
+  return res;
+}
+
+INTERCEPTOR(void, free, void *p) {
+  // There are only a few early allocation requests,
+  // so we simply skip the free.
+  if (isInEarlyAllocBuf(p))
+    return;
+  REAL(free)(p);
+}
+
+INTERCEPTOR(void *, valloc, uptr size) {
+  void *res = REAL(valloc)(size);
+  if (res)
+    tysan_set_type_unknown(res, size);
+  return res;
+}
+
+#if SANITIZER_INTERCEPT_MEMALIGN
+INTERCEPTOR(void *, memalign, uptr alignment, uptr size) {
+  void *res = REAL(memalign)(alignment, size);
+  if (res)
+    tysan_set_type_unknown(res, size);
+  return res;
+}
+#define TYSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
+#else
+#define TYSAN_MAYBE_INTERCEPT_MEMALIGN
+#endif // SANITIZER_INTERCEPT_MEMALIGN
+
+#if SANITIZER_INTERCEPT___LIBC_MEMALIGN
+INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {
+  void *res = REAL(__libc_memalign)(alignment, size);
+  if (res)
+    tysan_set_type_unknown(res, size);
+  return res;
+}
+#define TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN                                  \
+  INTERCEPT_FUNCTION(__libc_memalign)
+#else
+#define TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN
+#endif // SANITIZER_INTERCEPT___LIBC_MEMALIGN
+
+#if SANITIZER_INTERCEPT_PVALLOC
+INTERCEPTOR(void *, pvalloc, uptr size) {
+  void *res = REAL(pvalloc)(size);
+  if (res)
+    tysan_set_type_unknown(res, size);
+  return res;
+}
+#define TYSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
+#else
+#define TYSAN_MAYBE_INTERCEPT_PVALLOC
+#endif // SANITIZER_INTERCEPT_PVALLOC
+
+#if SANITIZER_INTERCEPT_ALIGNED_ALLOC
+INTERCEPTOR(void *, aligned_alloc, uptr alignment, uptr size) {
+  void *res = REAL(aligned_alloc)(alignment, size);
+  if (res)
+    tysan_set_type_unknown(res, size);
+  return res;
+}
+#define TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc)
+#else
+#define TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC
+#endif
+
+INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
+  int res = REAL(posix_memalign)(memptr, alignment, size);
+  if (res == 0 && *memptr)
+    tysan_set_type_unknown(*memptr, size);
+  return res;
+}
+
+namespace __tysan {
+void InitializeInterceptors() {
+  static int inited = 0;
+  CHECK_EQ(inited, 0);
+
+  // Instruct libc malloc to consume less memory.
+#if SANITIZER_LINUX
+  mallopt(1, 0);          // M_MXFAST
+  mallopt(-3, 32 * 1024); // M_MMAP_THRESHOLD
+#endif
+
+  INTERCEPT_FUNCTION(mmap);
+
+  INTERCEPT_FUNCTION(mmap64);
+
+  INTERCEPT_FUNCTION(strdup);
+#if TYSAN_INTERCEPT___STRDUP
+  INTERCEPT_FUNCTION(__strdup);
+#endif
+
+  INTERCEPT_FUNCTION(malloc);
+  INTERCEPT_FUNCTION(calloc);
+  INTERCEPT_FUNCTION(free);
+  INTERCEPT_FUNCTION(realloc);
+  INTERCEPT_FUNCTION(valloc);
+  TYSAN_MAYBE_INTERCEPT_MEMALIGN;
+  TYSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN;
+  TYSAN_MAYBE_INTERCEPT_PVALLOC;
+  TYSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC
+  INTERCEPT_FUNCTION(posix_memalign);
+
+  INTERCEPT_FUNCTION(memset);
+  INTERCEPT_FUNCTION(memmove);
+  INTERCEPT_FUNCTION(memcpy);
+
+  inited = 1;
+}
+} // namespace __tysan
diff --git a/compiler-rt/lib/tysan/tysan_platform.h b/compiler-rt/lib/tysan/tysan_platform.h
new file mode 100644
index 0000000000000..f01392885d939
--- /dev/null
+++ b/compiler-rt/lib/tysan/tysan_platform.h
@@ -0,0 +1,93 @@
+//===------------------------ tysan_platform.h ----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of TypeSanitizer.
+//
+// Platform specific information for TySan.
+//===----------------------------------------------------------------------===//
+
+#ifndef TYSAN_PLATFORM_H
+#define TYSAN_PLATFORM_H
+
+namespace __tysan {
+
+#if defined(__x86_64__) || SANITIZER_APPLE
+struct Mapping {
+  static const uptr kShadowAddr = 0x010000000000ull;
+  static const uptr kAppAddr = 0x550000000000ull;
+  static const uptr kAppMemMsk = ~0x780000000000ull;
+};
+#elif defined(__aarch64__)
+struct Mapping39 {
+  static const uptr kShadowAddr = 0x0800000000ull;
+  static const uptr kAppAddr = 0x5500000000ull;
+  static const uptr kAppMemMsk = ~0x7800000000ull;
+};
+
+struct Mapping42 {
+  static const uptr kShadowAddr = 0x10000000000ull;
+  static const uptr kAppAddr = 0x2aa00000000ull;
+  static const uptr kAppMemMsk = ~0x3c000000000ull;
+};
+
+struct Mapping48 {
+  static const uptr kShadowAddr = 0x0002000000000ull;
+  static const uptr kAppAddr = 0x0aaaa00000000ull;
+  static const uptr kAppMemMsk = ~0x0fff800000000ull;
+};
+#define TYSAN_RUNTIME_VMA 1
+#else
+#error "TySan not supported for this platform!"
+#endif
+
+#if TYSAN_RUNTIME_VMA
+extern int vmaSize;
+#endif
+
+enum MappingType { MAPPING_SHADOW_ADDR, MAPPING_APP_ADDR, MAPPING_APP_MASK };
+
+template <typename Mapping, int Type> uptr MappingImpl(void) {
+  switch (Type) {
+  case MAPPING_SHADOW_ADDR:
+    return Mapping::kShadowAddr;
+  case MAPPING_APP_ADDR:
+    return Mapping::kAppAddr;
+  case MAPPING_APP_MASK:
+    return Mapping::kAppMemMsk;
+  }
+}
+
+template <int Type> uptr MappingArchImpl(void) {
+#if defined(__aarch64__) && !SANITIZER_APPLE
+  switch (vmaSize) {
+  case 39:
+    return MappingImpl<Mapping39, Type>();
+  case 42:
+    return MappingImpl<Mapping42, Type>();
+  case 48:
+    return MappingImpl<Mapping48, Type>();
+  }
+  DCHECK(0);
+  return 0;
+#else
+  return MappingImpl<Mapping, Type>();
+#endif
+}
+
+ALWAYS_INLINE
+uptr ShadowAddr() { return MappingArchImpl<MAPPING_SHADOW_ADDR>(); }
+
+ALWAYS_INLINE
+uptr AppAddr() { return MappingArchImpl<MAPPING_APP_ADDR>(); }
+
+ALWAYS_INLINE
+uptr AppMask() { return MappingArchImpl<MAPPING_APP_MASK>(); }
+
+} // namespace __tysan
+
+#endif
diff --git a/compiler-rt/test/tysan/CMakeLists.txt b/compiler-rt/test/tysan/CMakeLists.txt
new file mode 100644
index 0000000000000..76f57501e854e
--- /dev/null
+++ b/compiler-rt/test/tysan/CMakeLists.txt
@@ -0,0 +1,32 @@
+set(TYSAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
+set(TYSAN_TESTSUITES)
+
+set(TYSAN_TEST_ARCH ${TYSAN_SUPPORTED_ARCH})
+if(APPLE)
+  darwin_filter_host_archs(TYSAN_SUPPORTED_ARCH TYSAN_TEST_ARCH)
+endif()
+
+foreach(arch ${TYSAN_TEST_ARCH})
+  set(TYSAN_TEST_TARGET_ARCH ${arch})
+  string(TOLOWER "-${arch}" TYSAN_TEST_CONFIG_SUFFIX)
+  get_test_cc_for_arch(${arch} TYSAN_TEST_TARGET_CC TYSAN_TEST_TARGET_CFLAGS)
+  string(TOUPPER ${arch} ARCH_UPPER_CASE)
+  set(CONFIG_NAME ${ARCH_UPPER_CASE}Config)
+
+  configure_lit_site_cfg(
+    ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
+    ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg.py)
+  list(APPEND TYSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME})
+endforeach()
+
+set(TYSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
+if(NOT COMPILER_RT_STANDALONE_BUILD)
+  list(APPEND TYSAN_TEST_DEPS tysan)
+endif()
+
+add_lit_testsuite(check-tysan "Running the TypeSanitizer tests"
+  ${TYSAN_TESTSUITES}
+  DEPENDS ${TYSAN_TEST_DEPS}
+  )
+set_target_properties(check-tysan PROPERTIES FOLDER "Compiler-RT Misc")
diff --git a/compiler-rt/test/tysan/anon-ns.cpp b/compiler-rt/test/tysan/anon-ns.cpp
new file mode 100644
index 0000000000000..681304411df31
--- /dev/null
+++ b/compiler-rt/test/tysan/anon-ns.cpp
@@ -0,0 +1,41 @@
+// RUN: %clangxx_tysan -O0 %s -c -o %t.o
+// RUN: %clangxx_tysan -O0 %s -DPMAIN -c -o %tm.o
+// RUN: %clangxx_tysan -O0 %t.o %tm.o -o %t
+// RUN: %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <iostream>
+
+// This test demonstrates that the types from anonymous namespaces are
+// different in different translation units (while the char* type is the same).
+
+namespace {
+struct X {
+  X(int i, int j) : a(i), b(j) {}
+  int a;
+  int b;
+};
+} // namespace
+
+#ifdef PMAIN
+void foo(void *context, int i);
+char fbyte(void *context);
+
+int main() {
+  X x(5, 6);
+  foo((void *)&x, 8);
+  std::cout << "fbyte: " << fbyte((void *)&x) << "\n";
+}
+#else
+void foo(void *context, int i) {
+  X *x = (X *)context;
+  x->b = i;
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: WRITE of size 4 at {{.*}} with type int (in (anonymous namespace)::X at offset 4) accesses an existing object of type int (in (anonymous namespace)::X at offset 4)
+  // CHECK: {{#0 0x.* in foo\(void\*, int\) .*anon-ns.cpp:}}[[@LINE-3]]
+}
+
+char fbyte(void *context) { return *(char *)context; }
+#endif
+
+// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation
diff --git a/compiler-rt/test/tysan/anon-same-struct.c b/compiler-rt/test/tysan/anon-same-struct.c
new file mode 100644
index 0000000000000..b9044f2a0a73c
--- /dev/null
+++ b/compiler-rt/test/tysan/anon-same-struct.c
@@ -0,0 +1,26 @@
+// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <stdio.h>
+
+// The two anonymous structs are structurally identical. As a result, we don't
+// report an aliasing violation here.
+// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation
+
+typedef struct {
+  int i1;
+} s1;
+typedef struct {
+  int i2;
+} s2;
+
+void f(s1 *s1p, s2 *s2p) {
+  s1p->i1 = 2;
+  s2p->i2 = 3;
+  printf("%i\n", s1p->i1);
+}
+
+int main() {
+  s1 s = {.i1 = 1};
+  f(&s, (s2 *)&s);
+}
diff --git a/compiler-rt/test/tysan/anon-struct.c b/compiler-rt/test/tysan/anon-struct.c
new file mode 100644
index 0000000000000..25f6633545928
--- /dev/null
+++ b/compiler-rt/test/tysan/anon-struct.c
@@ -0,0 +1,27 @@
+// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <stdio.h>
+
+typedef struct {
+  int i1, i1b;
+} s1;
+typedef struct {
+  int i2, i2b, i2c;
+} s2;
+
+void f(s1 *s1p, s2 *s2p) {
+  s1p->i1 = 2;
+  s2p->i2 = 3;
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: WRITE of size 4 at {{.*}} with type int (in <anonymous type> at offset 0) accesses an existing object of type int (in <anonymous type> at offset 0)
+  // CHECK: {{#0 0x.* in f .*anon-struct.c:}}[[@LINE-3]]
+  printf("%i\n", s1p->i1);
+}
+
+int main() {
+  s1 s = {.i1 = 1, .i1b = 5};
+  f(&s, (s2 *)&s);
+}
+
+// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation
diff --git a/compiler-rt/test/tysan/basic.c b/compiler-rt/test/tysan/basic.c
new file mode 100644
index 0000000000000..8e66e1a721383
--- /dev/null
+++ b/compiler-rt/test/tysan/basic.c
@@ -0,0 +1,65 @@
+// RUN: %clang_tysan -O0 %s -o %t && %run %t 10 >%t.out.0 2>&1
+// RUN: FileCheck %s < %t.out.0
+// RUN: %clang_tysan -O2 %s -o %t && %run %t 10 >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void __attribute__((noinline)) add_flt(float *a) {
+  *a += 2.0f;
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: READ of size 4 at {{.*}} with type float accesses an existing object of type int
+  // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-3]]
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: WRITE of size 4 at {{.*}} with type float accesses an existing object of type int
+  // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-6]]
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: READ of size 4 at {{.*}} with type float accesses an existing object of type long
+  // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-9]]
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: WRITE of size 4 at {{.*}} with type float accesses an existing object of type long
+  // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-12]]
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: READ of size 4 at {{.*}} with type float accesses part of an existing object of type long that starts at offset -4
+  // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-15]]
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: WRITE of size 4 at {{.*}} with type float accesses part of an existing object of type long that starts at offset -4
+  // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-18]]
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: READ of size 4 at {{.*}} with type float partially accesses an object of type short that starts at offset 2
+  // CHECK: {{#0 0x.* in add_flt .*basic.c:}}[[@LINE-21]]
+}
+
+int main(int argc, char *argv[]) {
+  int x = atoi(argv[1]);
+  add_flt((float *)&x);
+  printf("x = %d\n", x);
+
+  long y = x;
+  add_flt((float *)&y);
+  printf("y = %ld\n", y);
+
+  add_flt(((float *)&y) + 1);
+  printf("y = %ld\n", y);
+
+  char *mem = (char *)malloc(4 * sizeof(short));
+  memset(mem, 0, 4 * sizeof(short));
+  *(short *)(mem + 2) = x;
+  add_flt((float *)mem);
+  short s1 = *(short *)mem;
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: READ of size 2 at {{.*}} with type short accesses an existing object of type float
+  // CHECK: {{#0 0x.* in main .*basic.c:}}[[@LINE-3]]
+  short s2 = *(short *)(mem + 2);
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: READ of size 2 at {{.*}} with type short accesses part of an existing object of type float that starts at offset -2
+  // CHECK: {{#0 0x.* in main .*basic.c:}}[[@LINE-3]]
+  printf("m[0] = %d, m[1] = %d\n", s1, s2);
+  free(mem);
+
+  return 0;
+}
+
+// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation
diff --git a/compiler-rt/test/tysan/char-memcpy.c b/compiler-rt/test/tysan/char-memcpy.c
new file mode 100644
index 0000000000000..ebbb6b53d0f37
--- /dev/null
+++ b/compiler-rt/test/tysan/char-memcpy.c
@@ -0,0 +1,45 @@
+// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out.0 2>&1
+// RUN: FileCheck %s < %t.out.0
+// RUN: %clang_tysan -O2 %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <stdio.h>
+
+// There's no type-based-aliasing violation here: the memcpy is implemented
+// using only char* or unsigned char* (both of which may alias anything).
+// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation
+
+void my_memcpy_uchar(void *dest, void *src, int n) {
+  unsigned char *p = dest, *q = src, *end = p + n;
+  while (p < end)
+    *p++ = *q++;
+}
+
+void my_memcpy_char(void *dest, void *src, int n) {
+  char *p = dest, *q = src, *end = p + n;
+  while (p < end)
+    *p++ = *q++;
+}
+
+void test_uchar() {
+  struct S {
+    short x;
+    short *r;
+  } s = {10, &s.x}, s2;
+  my_memcpy_uchar(&s2, &s, sizeof(struct S));
+  printf("%d\n", *(s2.r));
+}
+
+void test_char() {
+  struct S {
+    short x;
+    short *r;
+  } s = {10, &s.x}, s2;
+  my_memcpy_char(&s2, &s, sizeof(struct S));
+  printf("%d\n", *(s2.r));
+}
+
+int main() {
+  test_uchar();
+  test_char();
+}
diff --git a/compiler-rt/test/tysan/global.c b/compiler-rt/test/tysan/global.c
new file mode 100644
index 0000000000000..247ee768a8162
--- /dev/null
+++ b/compiler-rt/test/tysan/global.c
@@ -0,0 +1,31 @@
+// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+#include <stdlib.h>
+#include <string.h>
+
+float P;
+long L;
+
+int main() {
+  *(int *)&P = 5;
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: WRITE of size 4 at {{.*}} with type int accesses an existing object of type float
+  // CHECK: {{#0 0x.* in main .*global.c:}}[[@LINE-3]]
+
+  void *mem = malloc(sizeof(long));
+  *(int *)mem = 6;
+  memcpy(mem, &L, sizeof(L));
+  *(int *)mem = 8;
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: WRITE of size 4 at {{.*}} with type int accesses an existing object of type long
+  // CHECK: {{#0 0x.* in main .*global.c:}}[[@LINE-3]]
+  int r = *(((int *)mem) + 1);
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: READ of size 4 at {{.*}} with type int accesses part of an existing object of type long that starts at offset -4
+  // CHECK: {{#0 0x.* in main .*global.c:}}[[@LINE-3]]
+  free(mem);
+
+  return r;
+}
+
+// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation
diff --git a/compiler-rt/test/tysan/int-long.c b/compiler-rt/test/tysan/int-long.c
new file mode 100644
index 0000000000000..b7956c07376e8
--- /dev/null
+++ b/compiler-rt/test/tysan/int-long.c
@@ -0,0 +1,21 @@
+// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <stdio.h>
+
+long foo(int *x, long *y) {
+  *x = 0;
+  *y = 1;
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: WRITE of size 8 at {{.*}} with type long accesses an existing object of type int
+  // CHECK: {{#0 0x.* in foo .*int-long.c:}}[[@LINE-3]]
+
+  return *x;
+}
+
+int main(void) {
+  long l;
+  printf("%ld\n", foo((int *)&l, &l));
+}
+
+// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation
diff --git a/compiler-rt/test/tysan/lit.cfg.py b/compiler-rt/test/tysan/lit.cfg.py
new file mode 100644
index 0000000000000..05c8f0664d5e6
--- /dev/null
+++ b/compiler-rt/test/tysan/lit.cfg.py
@@ -0,0 +1,139 @@
+# -*- Python -*-
+
+import os
+import platform
+import re
+
+import lit.formats
+
+# Get shlex.quote if available (added in 3.3), and fall back to pipes.quote if
+# it's not available.
+try:
+  import shlex
+  sh_quote = shlex.quote
+except:
+  import pipes
+  sh_quote = pipes.quote
+
+def get_required_attr(config, attr_name):
+  attr_value = getattr(config, attr_name, None)
+  if attr_value == None:
+    lit_config.fatal(
+      "No attribute %r in test configuration! You may need to run "
+      "tests from your build directory or add this attribute "
+      "to lit.site.cfg.py " % attr_name)
+  return attr_value
+
+def push_dynamic_library_lookup_path(config, new_path):
+  if platform.system() == 'Windows':
+    dynamic_library_lookup_var = 'PATH'
+  elif platform.system() == 'Darwin':
+    dynamic_library_lookup_var = 'DYLD_LIBRARY_PATH'
+  else:
+    dynamic_library_lookup_var = 'LD_LIBRARY_PATH'
+
+  new_ld_library_path = os.path.pathsep.join(
+    (new_path, config.environment.get(dynamic_library_lookup_var, '')))
+  config.environment[dynamic_library_lookup_var] = new_ld_library_path
+
+  if platform.system() == 'FreeBSD':
+    dynamic_library_lookup_var = 'LD_32_LIBRARY_PATH'
+    new_ld_32_library_path = os.path.pathsep.join(
+      (new_path, config.environment.get(dynamic_library_lookup_var, '')))
+    config.environment[dynamic_library_lookup_var] = new_ld_32_library_path
+
+  if platform.system() == 'SunOS':
+    dynamic_library_lookup_var = 'LD_LIBRARY_PATH_32'
+    new_ld_library_path_32 = os.path.pathsep.join(
+      (new_path, config.environment.get(dynamic_library_lookup_var, '')))
+    config.environment[dynamic_library_lookup_var] = new_ld_library_path_32
+
+    dynamic_library_lookup_var = 'LD_LIBRARY_PATH_64'
+    new_ld_library_path_64 = os.path.pathsep.join(
+      (new_path, config.environment.get(dynamic_library_lookup_var, '')))
+    config.environment[dynamic_library_lookup_var] = new_ld_library_path_64
+
+# Setup config name.
+config.name = 'TypeSanitizer' + config.name_suffix
+
+# Platform-specific default TYSAN_OPTIONS for lit tests.
+default_tysan_opts = list(config.default_sanitizer_opts)
+
+# On Darwin, leak checking is not enabled by default. Enable on macOS
+# tests to prevent regressions
+if config.host_os == 'Darwin' and config.apple_platform == 'osx':
+  default_tysan_opts += ['detect_leaks=1']
+
+default_tysan_opts_str = ':'.join(default_tysan_opts)
+if default_tysan_opts_str:
+  config.environment['TYSAN_OPTIONS'] = default_tysan_opts_str
+  default_tysan_opts_str += ':'
+config.substitutions.append(('%env_tysan_opts=',
+                             'env TYSAN_OPTIONS=' + default_tysan_opts_str))
+
+# Setup source root.
+config.test_source_root = os.path.dirname(__file__)
+
+if config.host_os not in ['FreeBSD', 'NetBSD']:
+  libdl_flag = "-ldl"
+else:
+  libdl_flag = ""
+
+# GCC-ASan doesn't link in all the necessary libraries automatically, so
+# we have to do it ourselves.
+if config.compiler_id == 'GNU':
+  extra_link_flags = ["-pthread", "-lstdc++", libdl_flag]
+else:
+  extra_link_flags = []
+
+# Setup default compiler flags used with -fsanitize=address option.
+# FIXME: Review the set of required flags and check if it can be reduced.
+target_cflags = [get_required_attr(config, "target_cflags")] + extra_link_flags
+target_cxxflags = config.cxx_mode_flags + target_cflags
+clang_tysan_static_cflags = (["-fsanitize=type",
+                            "-mno-omit-leaf-frame-pointer",
+                            "-fno-omit-frame-pointer",
+                            "-fno-optimize-sibling-calls"] +
+                            config.debug_info_flags + target_cflags)
+if config.target_arch == 's390x':
+  clang_tysan_static_cflags.append("-mbackchain")
+clang_tysan_static_cxxflags = config.cxx_mode_flags + clang_tysan_static_cflags
+
+clang_tysan_cflags = clang_tysan_static_cflags 
+clang_tysan_cxxflags = clang_tysan_static_cxxflags
+
+def build_invocation(compile_flags):
+  return " " + " ".join([config.clang] + compile_flags) + " "
+
+config.substitutions.append( ("%clang ", build_invocation(target_cflags)) )
+config.substitutions.append( ("%clangxx ", build_invocation(target_cxxflags)) )
+config.substitutions.append( ("%clang_tysan ", build_invocation(clang_tysan_cflags)) )
+config.substitutions.append( ("%clangxx_tysan ", build_invocation(clang_tysan_cxxflags)) )
+
+
+# FIXME: De-hardcode this path.
+tysan_source_dir = os.path.join(
+  get_required_attr(config, "compiler_rt_src_root"), "lib", "tysan")
+python_exec = sh_quote(get_required_attr(config, "python_executable"))
+
+# Set LD_LIBRARY_PATH to pick dynamic runtime up properly.
+push_dynamic_library_lookup_path(config, config.compiler_rt_libdir)
+
+# Default test suffixes.
+config.suffixes = ['.c', '.cpp']
+
+if config.host_os == 'Darwin':
+  config.suffixes.append('.mm')
+
+if config.host_os == 'Windows':
+  config.substitutions.append(('%fPIC', ''))
+  config.substitutions.append(('%fPIE', ''))
+  config.substitutions.append(('%pie', ''))
+else:
+  config.substitutions.append(('%fPIC', '-fPIC'))
+  config.substitutions.append(('%fPIE', '-fPIE'))
+  config.substitutions.append(('%pie', '-pie'))
+
+# Only run the tests on supported OSs.
+if config.host_os not in ['Linux', 'Darwin',]:
+  config.unsupported = True
diff --git a/compiler-rt/test/tysan/lit.site.cfg.py.in b/compiler-rt/test/tysan/lit.site.cfg.py.in
new file mode 100644
index 0000000000000..b56dce4fed7a2
--- /dev/null
+++ b/compiler-rt/test/tysan/lit.site.cfg.py.in
@@ -0,0 +1,17 @@
+ at LIT_SITE_CFG_IN_HEADER@
+
+# Tool-specific config options.
+config.name_suffix = "@TYSAN_TEST_CONFIG_SUFFIX@"
+config.target_cflags = "@TYSAN_TEST_TARGET_CFLAGS@"
+config.clang = "@TYSAN_TEST_TARGET_CC@"
+config.bits = "@TYSAN_TEST_BITS@"
+config.arm_thumb = "@COMPILER_RT_ARM_THUMB@"
+config.apple_platform = "@TYSAN_TEST_APPLE_PLATFORM@"
+config.apple_platform_min_deployment_target_flag = "@TYSAN_TEST_MIN_DEPLOYMENT_TARGET_FLAG@"
+config.target_arch = "@TYSAN_TEST_TARGET_ARCH@"
+
+# Load common config for all compiler-rt lit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
+
+# Load tool-specific config that would do the real work.
+lit_config.load_config(config, "@TYSAN_LIT_SOURCE_DIR@/lit.cfg.py")
diff --git a/compiler-rt/test/tysan/ptr-float.c b/compiler-rt/test/tysan/ptr-float.c
new file mode 100644
index 0000000000000..61fa5f1afd70a
--- /dev/null
+++ b/compiler-rt/test/tysan/ptr-float.c
@@ -0,0 +1,19 @@
+// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+float *P;
+void zero_array() {
+  int i;
+  for (i = 0; i < 1; ++i)
+    P[i] = 0.0f;
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: WRITE of size 4 at {{.*}} with type float accesses an existing object of type any pointer
+  // CHECK: {{#0 0x.* in zero_array .*ptr-float.c:}}[[@LINE-3]]
+}
+
+int main() {
+  P = (float *)&P;
+  zero_array();
+}
+
+// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation
diff --git a/compiler-rt/test/tysan/struct-offset-multiple-compilation-units.cpp b/compiler-rt/test/tysan/struct-offset-multiple-compilation-units.cpp
new file mode 100644
index 0000000000000..f7baa14d15aff
--- /dev/null
+++ b/compiler-rt/test/tysan/struct-offset-multiple-compilation-units.cpp
@@ -0,0 +1,51 @@
+// RUN: %clangxx_tysan -O0 %s -c -o %t.o
+// RUN: %clangxx_tysan -O0 %s -DPMAIN -c -o %tm.o
+// RUN: %clangxx_tysan -O0 %s -DPINIT -c -o %tinit.o
+// RUN: %clangxx_tysan -O0 %t.o %tm.o %tinit.o -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern "C" {
+typedef struct X {
+  int *start;
+  int *end;
+  int i;
+} X;
+};
+
+#ifdef PMAIN
+int foo(struct X *);
+void bar(struct X *);
+void init(struct X *);
+
+int main() {
+  struct X x;
+  init(&x);
+  printf("%d\n", foo(&x));
+  free(x.start);
+  return 0;
+}
+
+#elif PINIT
+
+void init(struct X *x) {
+  x->start = (int *)calloc(100, sizeof(int));
+  x->end = x->start + 99;
+  x->i = 0;
+}
+
+#else
+
+__attribute__((noinline)) int foo(struct X *x) {
+  if (x->start < x->end)
+    return 30;
+  return 10;
+}
+
+void bar(struct X *x) { x->end = NULL; }
+
+#endif
+
+// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation
diff --git a/compiler-rt/test/tysan/struct-offset.c b/compiler-rt/test/tysan/struct-offset.c
new file mode 100644
index 0000000000000..7295e0ae121ed
--- /dev/null
+++ b/compiler-rt/test/tysan/struct-offset.c
@@ -0,0 +1,26 @@
+// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <stdio.h>
+#include <stdlib.h>
+
+struct X {
+  int i;
+  int j;
+};
+
+int foo(struct X *p, struct X *q) {
+  q->j = 1;
+  p->i = 0;
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: WRITE of size 4 at {{.*}} with type int (in X at offset 0) accesses an existing object of type int (in X at offset 4)
+  // CHECK: {{#0 0x.* in foo .*struct-offset.c:}}[[@LINE-3]]
+  return q->j;
+}
+
+int main() {
+  unsigned char *p = malloc(3 * sizeof(int));
+  printf("%i\n", foo((struct X *)(p + sizeof(int)), (struct X *)p));
+}
+
+// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation
diff --git a/compiler-rt/test/tysan/struct.c b/compiler-rt/test/tysan/struct.c
new file mode 100644
index 0000000000000..f7ecef5967624
--- /dev/null
+++ b/compiler-rt/test/tysan/struct.c
@@ -0,0 +1,39 @@
+// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <stdio.h>
+
+typedef struct S1 {
+  int i1;
+} s1;
+typedef struct S2 {
+  int i2;
+} s2;
+
+void g(int *i) {
+  *i = 5;
+  printf("%i\n", *i);
+}
+
+void h(char *c) {
+  *c = 5;
+  printf("%i\n", (int)*c);
+}
+
+void f(s1 *s1p, s2 *s2p) {
+  s1p->i1 = 2;
+  s2p->i2 = 3;
+  // CHECK: ERROR: TypeSanitizer: type-aliasing-violation
+  // CHECK: WRITE of size 4 at {{.*}} with type int (in S2 at offset 0) accesses an existing object of type int (in S1 at offset 0)
+  // CHECK: {{#0 0x.* in f .*struct.c:}}[[@LINE-3]]
+  printf("%i\n", s1p->i1);
+}
+
+int main() {
+  s1 s = {.i1 = 1};
+  f(&s, (s2 *)&s);
+  g(&s.i1);
+  h((char *)&s.i1);
+}
+
+// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation
diff --git a/compiler-rt/test/tysan/union-wr-wr.c b/compiler-rt/test/tysan/union-wr-wr.c
new file mode 100644
index 0000000000000..6414bbfcf9d95
--- /dev/null
+++ b/compiler-rt/test/tysan/union-wr-wr.c
@@ -0,0 +1,18 @@
+// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <stdio.h>
+
+// CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation
+
+int main() {
+  union {
+    int i;
+    short s;
+  } u;
+
+  u.i = 42;
+  u.s = 1;
+
+  printf("%d\n", u.i);
+}
diff --git a/compiler-rt/test/tysan/violation-pr45282.c b/compiler-rt/test/tysan/violation-pr45282.c
new file mode 100644
index 0000000000000..f3583d6be6f6a
--- /dev/null
+++ b/compiler-rt/test/tysan/violation-pr45282.c
@@ -0,0 +1,32 @@
+// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// https://github.com/llvm/llvm-project/issues/45282
+
+#include <stdio.h>
+
+int main(void) {
+
+  double a[29], b[20];
+  int i, j;
+
+  for (i = 0; i < 20; ++i) {
+    b[i] = 2.01f + 1.f;
+    ((float *)a)[i] = 2.01f * 2.0145f;
+    ((float *)a + 38)[i] = 2.01f * 1.0123f;
+  }
+
+  // CHECK:      TypeSanitizer: type-aliasing-violation on address
+  // CHECK-NEXT: WRITE of size 8 at {{.+}} with type double accesses an existing object of type float
+  // CHECK-NEXT:   in main violation-pr45282.c:25
+
+  // loop of problems
+  for (j = 2; j <= 4; ++j) {
+    a[j - 1] = ((float *)a)[j] * ((float *)a + 38)[j - 1];
+    ((float *)a + 38)[j - 1] = ((float *)a)[j - 1] + b[j - 1];
+  }
+
+  printf("((float *)a + 38)[2] = %f\n", ((float *)a + 38)[2]);
+
+  return 0;
+}
diff --git a/compiler-rt/test/tysan/violation-pr47137.c b/compiler-rt/test/tysan/violation-pr47137.c
new file mode 100644
index 0000000000000..3987128ff6fc6
--- /dev/null
+++ b/compiler-rt/test/tysan/violation-pr47137.c
@@ -0,0 +1,40 @@
+// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// https://github.com/llvm/llvm-project/issues/47137
+#include <stdio.h>
+#include <stdlib.h>
+
+void f(int m) {
+  int n = (4 * m + 2) / 3;
+  uint64_t *a = malloc(n * sizeof(uint64_t));
+  uint64_t *b = malloc(n * sizeof(uint64_t));
+  uint64_t aa[] = {0xffff3e0000000001, 0x22eaf0b680a88c16, 0x5a65d25ac40e20f3,
+                   0x34e7ac346236953e, 0x9dea3e0a26c6ba89, 0x0000000000000000,
+                   0x0000000000000000, 0x0000000000000000};
+  uint64_t bb[] = {0x0000000024c0ffff, 0x000000004634d940, 0x00000000219d18ef,
+                   0x0000000000154519, 0x000000000000035f, 0x0000000000000000,
+                   0x0000000000000000, 0x0000000000000000};
+  char l[20];
+  l[0] = 0;
+  for (int i = 0; i < n; i++) {
+    a[i] = aa[i] + l[0] - '0';
+    b[i] = bb[i] + l[0] - '0';
+  }
+
+  // CHECK:      TypeSanitizer: type-aliasing-violation on address
+  // CHECK-NEXT: READ of size 2 at {{.+}} with type short accesses an existing object of type long long
+  // CHECK-NEXT:    in f violation-pr47137.c:30
+  for (int i = 0, j = 0; j < 4 * m; i += 4, j += 3) {
+    for (int k = 0; k < 3; k++) {
+      ((uint16_t *)a)[j + k] = ((uint16_t *)a)[i + k];
+      ((uint16_t *)b)[j + k] = ((uint16_t *)b)[i + k];
+    }
+  }
+
+  printf("a: %016llx\n", a[0]);
+  free(a);
+  free(b);
+}
+
+int main() { f(6); }
diff --git a/compiler-rt/test/tysan/violation-pr51837.c b/compiler-rt/test/tysan/violation-pr51837.c
new file mode 100644
index 0000000000000..d49a813933d65
--- /dev/null
+++ b/compiler-rt/test/tysan/violation-pr51837.c
@@ -0,0 +1,34 @@
+// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <stdint.h>
+#include <stdio.h>
+
+// CHECK-NOT: TypeSanitizer
+
+union a {
+  int16_t b;
+  uint64_t c;
+} d;
+
+uint64_t *e = &d.c;
+static uint16_t f(int16_t a, int32_t b, uint64_t c);
+static int64_t g(int32_t aa, uint8_t h, union a bb) {
+  int16_t *i = &d.b;
+  f(0, h, 0);
+  *i = h;
+  return 0;
+}
+uint16_t f(int16_t a, int32_t b, uint64_t c) {
+  for (d.c = 0; 0;)
+    ;
+  *e = 0;
+  return 0;
+}
+
+int main() {
+  uint32_t j = 8;
+  g(1, j, d);
+  printf("%d\n", d.b);
+  return 0;
+}
diff --git a/compiler-rt/test/tysan/violation-pr62544.c b/compiler-rt/test/tysan/violation-pr62544.c
new file mode 100644
index 0000000000000..30610925ba385
--- /dev/null
+++ b/compiler-rt/test/tysan/violation-pr62544.c
@@ -0,0 +1,24 @@
+// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// https://github.com/llvm/llvm-project/issues/62544
+
+int printf(const char *, ...);
+int a, b, c;
+long d;
+int main() {
+  short *e = &a;
+  int *f = &a;
+  *f = 0;
+  for (; b <= 9; b++) {
+    int **g = &f;
+    *f = d;
+    *g = &c;
+  }
+
+  // CHECK:      TypeSanitizer: type-aliasing-violation on address
+  // CHECK-NEXT: WRITE of size 2 at {{.+}} with type short accesses an existing object of type int
+  // CHECK-NEXT:   in main violation-pr62544.c:22
+  *e = 3;
+  printf("%d\n", a);
+}
diff --git a/compiler-rt/test/tysan/violation-pr62828.cpp b/compiler-rt/test/tysan/violation-pr62828.cpp
new file mode 100644
index 0000000000000..33003df9761f5
--- /dev/null
+++ b/compiler-rt/test/tysan/violation-pr62828.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// https://github.com/llvm/llvm-project/issues/62828
+#include <stdio.h>
+
+typedef int int_v8[8];
+typedef short short_v8[8];
+short *test1(int_v8 *cast_c_array, short_v8 *shuf_c_array1, int *ptr) {
+  int *input1 = reinterpret_cast<int *>(((int_v8 *)(cast_c_array)));
+  short *input2 = reinterpret_cast<short *>(reinterpret_cast<int_v8 *>(input1));
+
+  short *output1 = reinterpret_cast<short *>(((short_v8 *)(shuf_c_array1)));
+  short *output2 =
+      reinterpret_cast<short *>(reinterpret_cast<short_v8 *>(output1));
+
+  for (int r = 0; r < 8; ++r) {
+    int tmp = (int)((r * 4) + ptr[r]);
+    if ((ptr[r] / 4) == 0) {
+      int *input = reinterpret_cast<int *>(((int_v8 *)(cast_c_array)));
+      input[r] = tmp;
+    }
+  }
+
+  // CHECK:      ERROR: TypeSanitizer: type-aliasing-violation on address
+  // CHECK-NEXT: READ of size 2 at {{.+}} with type short accesses an existing object of type int
+  // CHECK-NEXT:    in test1(int (*) [8], short (*) [8], int*) violation-pr62828.cpp:29
+  for (int i3 = 0; i3 < 4; ++i3) {
+    output2[i3] = input2[(i3 * 2)];
+  }
+  return output2;
+}
+
+int main() {
+  int_v8 in[4] = {{4, 4, 4, 4}};
+  short_v8 out[4] = {{0}};
+  int ptr[8] = {2};
+  test1(in, out, ptr);
+  short *p = reinterpret_cast<short *>(out);
+  for (int i = 0; i < 32; i++) {
+    printf("%d ", p[i]);
+  }
+  return 0;
+}
diff --git a/compiler-rt/test/tysan/violation-pr68655.cpp b/compiler-rt/test/tysan/violation-pr68655.cpp
new file mode 100644
index 0000000000000..ac20f8c94e1ff
--- /dev/null
+++ b/compiler-rt/test/tysan/violation-pr68655.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// https://github.com/llvm/llvm-project/issues/68655
+struct S1 {
+  long long a;
+  long long b;
+};
+
+// CHECK: TypeSanitizer: type-aliasing-violation on address
+// CHECK-NEXT:  READ of size 4 at {{.+}} with type int accesses an existing object of type long long (in S1 at offset 0)
+// CHECK-NEXT: in copyMem(S1*, S1*) violation-pr68655.cpp:19
+
+void inline copyMem(S1 *dst, S1 *src) {
+  unsigned *d = reinterpret_cast<unsigned *>(dst);
+  unsigned *s = reinterpret_cast<unsigned *>(src);
+
+  for (int i = 0; i < sizeof(S1) / sizeof(unsigned); i++) {
+    *d = *s;
+    d++;
+    s++;
+  }
+}
+
+void math(S1 *dst, int *srcA, int idx_t) {
+  S1 zero[4];
+  for (int i = 0; i < 2; i++) {
+    zero[i].a = i + idx_t;
+    zero[i].b = i * idx_t;
+  }
+
+  copyMem(&dst[idx_t], &zero[srcA[idx_t]]);
+}
+
+int main() {
+  S1 dst = {0};
+  int Src[2] = {0, 0};
+  math(&dst, &Src[0], 0);
+  return 0;
+}
diff --git a/compiler-rt/test/tysan/violation-pr86685.c b/compiler-rt/test/tysan/violation-pr86685.c
new file mode 100644
index 0000000000000..fe4fd82af5fdd
--- /dev/null
+++ b/compiler-rt/test/tysan/violation-pr86685.c
@@ -0,0 +1,29 @@
+// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <stdio.h>
+#include <stdlib.h>
+
+// Violation reported in https://github.com/llvm/llvm-project/issues/86685.
+void foo(int *s, float *f, long n) {
+  for (long i = 0; i < n; ++i) {
+    *f = 2;
+    if (i == 1)
+      break;
+
+    // CHECK:      TypeSanitizer: type-aliasing-violation on address
+    // CHECK-NEXT: WRITE of size 4 at {{.+}} with type int accesses an existing object of type float
+    // CHECK-NEXT:   #0 {{.+}} in foo violation-pr86685.c:17
+    *s = 4;
+  }
+}
+
+int main(void) {
+  union {
+    int s;
+    float f;
+  } u = {0};
+  foo(&u.s, &u.f, 2);
+  printf("%.f\n", u.f);
+  return 0;
+}



More information about the llvm-branch-commits mailing list