[llvm-branch-commits] [clang] [compiler-rt] [llvm] [TySan] A Type Sanitizer (Runtime Library) (PR #76261)
Florian Hahn via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Apr 22 14:17:28 PDT 2024
https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/76261
>From 58839969d139a2e492ac217a5b49ac345ed73497 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 22 Dec 2023 19:18:29 +0000
Subject: [PATCH 1/4] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20ch?=
=?UTF-8?q?anges=20to=20main=20this=20commit=20is=20based=20on?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Created using spr 1.3.4
[skip ci]
---
llvm/include/llvm/Bitcode/LLVMBitCodes.h | 1 +
llvm/include/llvm/IR/Attributes.td | 4 +
.../Instrumentation/TypeSanitizer.h | 38 +
llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp | 28 +-
llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 2 +
llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 2 +
llvm/lib/CodeGen/ShrinkWrap.cpp | 1 +
llvm/lib/Passes/PassBuilder.cpp | 1 +
llvm/lib/Passes/PassRegistry.def | 2 +
.../Transforms/Instrumentation/CMakeLists.txt | 1 +
.../Instrumentation/TypeSanitizer.cpp | 873 ++++++++++++++++++
llvm/lib/Transforms/Utils/CodeExtractor.cpp | 1 +
.../TypeSanitizer/access-with-offfset.ll | 71 ++
.../Instrumentation/TypeSanitizer/alloca.ll | 29 +
.../Instrumentation/TypeSanitizer/anon.ll | 283 ++++++
.../TypeSanitizer/basic-nosan.ll | 93 ++
.../Instrumentation/TypeSanitizer/basic.ll | 214 +++++
.../Instrumentation/TypeSanitizer/byval.ll | 88 ++
.../Instrumentation/TypeSanitizer/globals.ll | 66 ++
.../TypeSanitizer/invalid-metadata.ll | 25 +
.../TypeSanitizer/memintrinsics.ll | 77 ++
.../TypeSanitizer/nosanitize.ll | 39 +
.../TypeSanitizer/sanitize-no-tbaa.ll | 180 ++++
.../TypeSanitizer/swifterror.ll | 24 +
24 files changed, 2137 insertions(+), 6 deletions(-)
create mode 100644 llvm/include/llvm/Transforms/Instrumentation/TypeSanitizer.h
create mode 100644 llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/access-with-offfset.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/alloca.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/anon.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/basic.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/byval.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/globals.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/memintrinsics.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/sanitize-no-tbaa.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/swifterror.ll
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index c6f0ddf29a6da8..8d3259336abba9 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -724,6 +724,7 @@ enum AttributeKindCodes {
ATTR_KIND_WRITABLE = 89,
ATTR_KIND_CORO_ONLY_DESTROY_WHEN_COMPLETE = 90,
ATTR_KIND_DEAD_ON_UNWIND = 91,
+ ATTR_KIND_SANITIZE_TYPE = 92,
};
enum ComdatSelectionKindCodes {
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index 864f87f3383891..beffa63bd81298 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -270,6 +270,9 @@ def SanitizeAddress : EnumAttr<"sanitize_address", [FnAttr]>;
/// ThreadSanitizer is on.
def SanitizeThread : EnumAttr<"sanitize_thread", [FnAttr]>;
+/// TypeSanitizer is on.
+def SanitizeType : EnumAttr<"sanitize_type", [FnAttr]>;
+
/// MemorySanitizer is on.
def SanitizeMemory : EnumAttr<"sanitize_memory", [FnAttr]>;
@@ -354,6 +357,7 @@ def : CompatRule<"isEqual<SanitizeThreadAttr>">;
def : CompatRule<"isEqual<SanitizeMemoryAttr>">;
def : CompatRule<"isEqual<SanitizeHWAddressAttr>">;
def : CompatRule<"isEqual<SanitizeMemTagAttr>">;
+def : CompatRule<"isEqual<SanitizeTypeAttr>">;
def : CompatRule<"isEqual<SafeStackAttr>">;
def : CompatRule<"isEqual<ShadowCallStackAttr>">;
def : CompatRule<"isEqual<UseSampleProfileAttr>">;
diff --git a/llvm/include/llvm/Transforms/Instrumentation/TypeSanitizer.h b/llvm/include/llvm/Transforms/Instrumentation/TypeSanitizer.h
new file mode 100644
index 00000000000000..a6cc56df35f14d
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Instrumentation/TypeSanitizer.h
@@ -0,0 +1,38 @@
+//===- Transforms/Instrumentation/TypeSanitizer.h - TySan Pass -----------===//
+//
+// 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 defines the type sanitizer pass.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_TYPESANITIZER_H
+#define LLVM_TRANSFORMS_INSTRUMENTATION_TYPESANITIZER_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+class Function;
+class FunctionPass;
+class Module;
+
+/// A function pass for tysan instrumentation.
+struct TypeSanitizerPass : public PassInfoMixin<TypeSanitizerPass> {
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
+ static bool isRequired() { return true; }
+};
+
+/// A module pass for tysan instrumentation.
+///
+/// Create ctor and init functions.
+struct ModuleTypeSanitizerPass : public PassInfoMixin<ModuleTypeSanitizerPass> {
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
+ static bool isRequired() { return true; }
+};
+
+} // namespace llvm
+#endif /* LLVM_TRANSFORMS_INSTRUMENTATION_TYPESANITIZER_H */
diff --git a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
index e4dc1a867f6f0c..bfa8a80518ccda 100644
--- a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
@@ -371,11 +371,27 @@ static bool isStructPathTBAA(const MDNode *MD) {
return isa<MDNode>(MD->getOperand(0)) && MD->getNumOperands() >= 3;
}
+// When using the TypeSanitizer, don't use TBAA information for alias analysis.
+// This might cause us to remove memory accesses that we need to verify at
+// runtime.
+static bool usingSanitizeType(const Value *V) {
+ const Function *F;
+
+ if (auto *I = dyn_cast<Instruction>(V))
+ F = I->getParent()->getParent();
+ else if (auto *A = dyn_cast<Argument>(V))
+ F = A->getParent();
+ else
+ return false;
+
+ return F->hasFnAttribute(Attribute::SanitizeType);
+}
+
AliasResult TypeBasedAAResult::alias(const MemoryLocation &LocA,
const MemoryLocation &LocB,
AAQueryInfo &AAQI, const Instruction *) {
- if (!EnableTBAA)
- return AliasResult::MayAlias;
+ if (!EnableTBAA || usingSanitizeType(LocA.Ptr) || usingSanitizeType(LocB.Ptr))
+ return AAResultBase::alias(LocA, LocB, AAQI, nullptr);
if (Aliases(LocA.AATags.TBAA, LocB.AATags.TBAA))
return AliasResult::MayAlias;
@@ -425,8 +441,8 @@ MemoryEffects TypeBasedAAResult::getMemoryEffects(const Function *F) {
ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call,
const MemoryLocation &Loc,
AAQueryInfo &AAQI) {
- if (!EnableTBAA)
- return ModRefInfo::ModRef;
+ if (!EnableTBAA || usingSanitizeType(Call))
+ return AAResultBase::getModRefInfo(Call, Loc, AAQI);
if (const MDNode *L = Loc.AATags.TBAA)
if (const MDNode *M = Call->getMetadata(LLVMContext::MD_tbaa))
@@ -439,8 +455,8 @@ ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call,
ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call1,
const CallBase *Call2,
AAQueryInfo &AAQI) {
- if (!EnableTBAA)
- return ModRefInfo::ModRef;
+ if (!EnableTBAA || usingSanitizeType(Call1))
+ return AAResultBase::getModRefInfo(Call1, Call2, AAQI);
if (const MDNode *M1 = Call1->getMetadata(LLVMContext::MD_tbaa))
if (const MDNode *M2 = Call2->getMetadata(LLVMContext::MD_tbaa))
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 8907f6fa4ff3fd..31e2d74fe570e8 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2058,6 +2058,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::SanitizeHWAddress;
case bitc::ATTR_KIND_SANITIZE_THREAD:
return Attribute::SanitizeThread;
+ case bitc::ATTR_KIND_SANITIZE_TYPE:
+ return Attribute::SanitizeType;
case bitc::ATTR_KIND_SANITIZE_MEMORY:
return Attribute::SanitizeMemory;
case bitc::ATTR_KIND_SPECULATIVE_LOAD_HARDENING:
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 8fca569a391baf..c925c367d17aaf 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -789,6 +789,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_SANITIZE_HWADDRESS;
case Attribute::SanitizeThread:
return bitc::ATTR_KIND_SANITIZE_THREAD;
+ case Attribute::SanitizeType:
+ return bitc::ATTR_KIND_SANITIZE_TYPE;
case Attribute::SanitizeMemory:
return bitc::ATTR_KIND_SANITIZE_MEMORY;
case Attribute::SpeculativeLoadHardening:
diff --git a/llvm/lib/CodeGen/ShrinkWrap.cpp b/llvm/lib/CodeGen/ShrinkWrap.cpp
index ab57d08e527e4d..f4e6f8001debf2 100644
--- a/llvm/lib/CodeGen/ShrinkWrap.cpp
+++ b/llvm/lib/CodeGen/ShrinkWrap.cpp
@@ -984,6 +984,7 @@ bool ShrinkWrap::isShrinkWrapEnabled(const MachineFunction &MF) {
!(MF.getFunction().hasFnAttribute(Attribute::SanitizeAddress) ||
MF.getFunction().hasFnAttribute(Attribute::SanitizeThread) ||
MF.getFunction().hasFnAttribute(Attribute::SanitizeMemory) ||
+ MF.getFunction().hasFnAttribute(Attribute::SanitizeType) ||
MF.getFunction().hasFnAttribute(Attribute::SanitizeHWAddress));
// If EnableShrinkWrap is set, it takes precedence on whatever the
// target sets. The rational is that we assume we want to test
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index f94bd422c6b592..fb56a65e41ec99 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -167,6 +167,7 @@
#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
+#include "llvm/Transforms/Instrumentation/TypeSanitizer.h"
#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Scalar/ADCE.h"
#include "llvm/Transforms/Scalar/AlignmentFromAssumptions.h"
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 82ce040c649626..5c9e16435f0ae9 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -138,6 +138,7 @@ MODULE_PASS("synthetic-counts-propagation", SyntheticCountsPropagation())
MODULE_PASS("trigger-crash", TriggerCrashPass())
MODULE_PASS("trigger-verifier-error", TriggerVerifierErrorPass())
MODULE_PASS("tsan-module", ModuleThreadSanitizerPass())
+MODULE_PASS("tysan-module", ModuleTypeSanitizerPass())
MODULE_PASS("verify", VerifierPass())
MODULE_PASS("view-callgraph", CallGraphViewerPass())
MODULE_PASS("wholeprogramdevirt", WholeProgramDevirtPass())
@@ -417,6 +418,7 @@ FUNCTION_PASS("tlshoist", TLSVariableHoistPass())
FUNCTION_PASS("transform-warning", WarnMissedTransformationsPass())
FUNCTION_PASS("trigger-verifier-error", TriggerVerifierErrorPass())
FUNCTION_PASS("tsan", ThreadSanitizerPass())
+FUNCTION_PASS("tysan", TypeSanitizerPass())
FUNCTION_PASS("typepromotion", TypePromotionPass(TM))
FUNCTION_PASS("unify-loop-exits", UnifyLoopExitsPass())
FUNCTION_PASS("vector-combine", VectorCombinePass())
diff --git a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
index 424f1d43360677..54211236e18643 100644
--- a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
+++ b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
@@ -20,6 +20,7 @@ add_llvm_component_library(LLVMInstrumentation
SanitizerBinaryMetadata.cpp
ValueProfileCollector.cpp
ThreadSanitizer.cpp
+ TypeSanitizer.cpp
HWAddressSanitizer.cpp
ADDITIONAL_HEADER_DIRS
diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
new file mode 100644
index 00000000000000..ed4aba4ad612d9
--- /dev/null
+++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
@@ -0,0 +1,873 @@
+//===----- TypeSanitizer.cpp - type-based-aliasing-violation detector -----===//
+//
+// 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, a type-based-aliasing-violation
+// detector.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Instrumentation/TypeSanitizer.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Analysis/MemoryLocation.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/MDBuilder.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
+#include "llvm/ProfileData/InstrProf.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MD5.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/Instrumentation.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Local.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
+
+#include <cctype>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "tysan"
+
+static const char *const kTysanModuleCtorName = "tysan.module_ctor";
+static const char *const kTysanInitName = "__tysan_init";
+static const char *const kTysanCheckName = "__tysan_check";
+static const char *const kTysanGVNamePrefix = "__tysan_v1_";
+
+static const char *const kTysanShadowMemoryAddress =
+ "__tysan_shadow_memory_address";
+static const char *const kTysanAppMemMask = "__tysan_app_memory_mask";
+
+static cl::opt<bool>
+ ClWritesAlwaysSetType("tysan-writes-always-set-type",
+ cl::desc("Writes always set the type"), cl::Hidden,
+ cl::init(false));
+
+STATISTIC(NumInstrumentedAccesses, "Number of instrumented accesses");
+
+static Regex AnonNameRegex("^_ZTS.*N[1-9][0-9]*_GLOBAL__N");
+
+namespace {
+
+/// TypeSanitizer: instrument the code in module to find type-based aliasing
+/// violations.
+struct TypeSanitizer {
+ TypeSanitizer(Module &M);
+ bool run(Function &F, const TargetLibraryInfo &TLI);
+ void instrumentGlobals();
+
+private:
+ typedef SmallDenseMap<const MDNode *, GlobalVariable *, 8>
+ TypeDescriptorsMapTy;
+ typedef SmallDenseMap<const MDNode *, std::string, 8> TypeNameMapTy;
+
+ void initializeCallbacks(Module &M);
+
+ Value *getShadowBase(Function &F);
+ Value *getAppMemMask(Function &F);
+
+ bool instrumentWithShadowUpdate(IRBuilder<> &IRB, const MDNode *TBAAMD,
+ Value *Ptr, uint64_t AccessSize, bool IsRead,
+ bool IsWrite, Value *&ShadowBase,
+ Value *&AppMemMask, bool ForceSetType,
+ bool SanitizeFunction,
+ TypeDescriptorsMapTy &TypeDescriptors,
+ const DataLayout &DL);
+ bool instrumentMemoryAccess(Instruction *I, MemoryLocation &MLoc,
+ Value *&ShadowBase, Value *&AppMemMask,
+ bool SanitizeFunction,
+ TypeDescriptorsMapTy &TypeDescriptors,
+ const DataLayout &DL);
+ bool instrumentMemInst(Value *I, Value *&ShadowBase, Value *&AppMemMask,
+ const DataLayout &DL);
+
+ std::string getAnonymousStructIdentifier(const MDNode *MD,
+ TypeNameMapTy &TypeNames);
+ bool generateTypeDescriptor(const MDNode *MD,
+ TypeDescriptorsMapTy &TypeDescriptors,
+ TypeNameMapTy &TypeNames, Module &M);
+ bool generateBaseTypeDescriptor(const MDNode *MD,
+ TypeDescriptorsMapTy &TypeDescriptors,
+ TypeNameMapTy &TypeNames, Module &M);
+
+ const Triple TargetTriple;
+ Type *IntptrTy;
+ uint64_t PtrShift;
+ IntegerType *OrdTy;
+
+ // Callbacks to run-time library are computed in doInitialization.
+ Function *TysanCheck;
+ Function *TysanCtorFunction;
+ Function *TysanGlobalsSetTypeFunction;
+};
+} // namespace
+
+TypeSanitizer::TypeSanitizer(Module &M)
+ : TargetTriple(Triple(M.getTargetTriple())) {
+ const DataLayout &DL = M.getDataLayout();
+ IntptrTy = DL.getIntPtrType(M.getContext());
+ PtrShift = countr_zero(IntptrTy->getPrimitiveSizeInBits() / 8);
+
+ TysanGlobalsSetTypeFunction = M.getFunction("__tysan_set_globals_types");
+ initializeCallbacks(M);
+}
+
+void TypeSanitizer::initializeCallbacks(Module &M) {
+ IRBuilder<> IRB(M.getContext());
+ OrdTy = IRB.getInt32Ty();
+
+ AttributeList Attr;
+ Attr = Attr.addFnAttribute(M.getContext(), Attribute::NoUnwind);
+ // Initialize the callbacks.
+ TysanCheck = cast<Function>(
+ M.getOrInsertFunction(kTysanCheckName, Attr, IRB.getVoidTy(),
+ IRB.getPtrTy(), // Pointer to data to be read.
+ OrdTy, // Size of the data in bytes.
+ IRB.getPtrTy(), // Pointer to type descriptor.
+ OrdTy // Flags.
+ )
+ .getCallee());
+
+ TysanCtorFunction = cast<Function>(
+ M.getOrInsertFunction(kTysanModuleCtorName, Attr, IRB.getVoidTy())
+ .getCallee());
+}
+
+void TypeSanitizer::instrumentGlobals() {
+ Module &M = *TysanCtorFunction->getParent();
+ initializeCallbacks(M);
+ TysanGlobalsSetTypeFunction = nullptr;
+
+ NamedMDNode *Globals = M.getNamedMetadata("llvm.tysan.globals");
+ if (!Globals)
+ return;
+
+ const DataLayout &DL = M.getDataLayout();
+ Value *ShadowBase = nullptr, *AppMemMask = nullptr;
+ TypeDescriptorsMapTy TypeDescriptors;
+ TypeNameMapTy TypeNames;
+
+ for (const auto &GMD : Globals->operands()) {
+ auto *GV = mdconst::dyn_extract_or_null<GlobalVariable>(GMD->getOperand(0));
+ if (!GV)
+ continue;
+ const MDNode *TBAAMD = cast<MDNode>(GMD->getOperand(1));
+ if (!generateBaseTypeDescriptor(TBAAMD, TypeDescriptors, TypeNames, M))
+ continue;
+
+ if (!TysanGlobalsSetTypeFunction) {
+ TysanGlobalsSetTypeFunction = Function::Create(
+ FunctionType::get(Type::getVoidTy(M.getContext()), false),
+ GlobalValue::InternalLinkage, "__tysan_set_globals_types", &M);
+ BasicBlock *BB =
+ BasicBlock::Create(M.getContext(), "", TysanGlobalsSetTypeFunction);
+ ReturnInst::Create(M.getContext(), BB);
+ }
+
+ IRBuilder<> IRB(
+ TysanGlobalsSetTypeFunction->getEntryBlock().getTerminator());
+ Type *AccessTy = GV->getValueType();
+ assert(AccessTy->isSized());
+ uint64_t AccessSize = DL.getTypeStoreSize(AccessTy);
+ instrumentWithShadowUpdate(IRB, TBAAMD, GV, AccessSize, false, false,
+ ShadowBase, AppMemMask, true, false,
+ TypeDescriptors, DL);
+ }
+
+ if (TysanGlobalsSetTypeFunction) {
+ IRBuilder<> IRB(TysanCtorFunction->getEntryBlock().getTerminator());
+ IRB.CreateCall(TysanGlobalsSetTypeFunction, {});
+ }
+}
+
+static void insertModuleCtor(Module &M) {
+ Function *TysanCtorFunction;
+ std::tie(TysanCtorFunction, std::ignore) =
+ createSanitizerCtorAndInitFunctions(M, kTysanModuleCtorName,
+ kTysanInitName, /*InitArgTypes=*/{},
+ /*InitArgs=*/{});
+
+ TypeSanitizer TySan(M);
+ TySan.instrumentGlobals();
+ appendToGlobalCtors(M, TysanCtorFunction, 0);
+}
+
+static const char LUT[] = "0123456789abcdef";
+
+static std::string encodeName(StringRef Name) {
+ size_t Length = Name.size();
+ std::string Output = kTysanGVNamePrefix;
+ Output.reserve(Output.size() + 3 * Length);
+ for (size_t i = 0; i < Length; ++i) {
+ const unsigned char c = Name[i];
+ if (isalnum((int)c)) {
+ Output.push_back(c);
+ continue;
+ }
+
+ if (c == '_') {
+ Output.append("__");
+ continue;
+ }
+
+ Output.push_back('_');
+ Output.push_back(LUT[c >> 4]);
+ Output.push_back(LUT[c & 15]);
+ }
+
+ return Output;
+}
+
+static bool isAnonymousNamespaceName(StringRef Name) {
+ // Types that are in an anonymous namespace are local to this module.
+ // FIXME: This should really be marked by the frontend in the metadata
+ // instead of having us guess this from the mangled name. Moreover, the regex
+ // here can pick up (unlikely) names in the non-reserved namespace (because
+ // it needs to search into the type to pick up cases where the type in the
+ // anonymous namespace is a template parameter, etc.).
+ return AnonNameRegex.match(Name);
+}
+
+std::string
+TypeSanitizer::getAnonymousStructIdentifier(const MDNode *MD,
+ TypeNameMapTy &TypeNames) {
+ MD5 Hash;
+
+ for (int i = 1, e = MD->getNumOperands(); i < e; i += 2) {
+ const MDNode *MemberNode = dyn_cast<MDNode>(MD->getOperand(i));
+ if (!MemberNode)
+ return "";
+
+ auto TNI = TypeNames.find(MemberNode);
+ std::string MemberName;
+ if (TNI != TypeNames.end()) {
+ MemberName = TNI->second;
+ } else {
+ if (MemberNode->getNumOperands() < 1)
+ return "";
+ MDString *MemberNameNode = dyn_cast<MDString>(MemberNode->getOperand(0));
+ if (!MemberNameNode)
+ return "";
+ MemberName = MemberNameNode->getString().str();
+ if (MemberName.empty())
+ MemberName = getAnonymousStructIdentifier(MemberNode, TypeNames);
+ if (MemberName.empty())
+ return "";
+ TypeNames[MemberNode] = MemberName;
+ }
+
+ Hash.update(MemberName);
+ Hash.update("\0");
+
+ uint64_t Offset =
+ mdconst::extract<ConstantInt>(MD->getOperand(i + 1))->getZExtValue();
+ Hash.update(utostr(Offset));
+ Hash.update("\0");
+ }
+
+ MD5::MD5Result HashResult;
+ Hash.final(HashResult);
+ return "__anonymous_" + std::string(HashResult.digest().str());
+}
+
+bool TypeSanitizer::generateBaseTypeDescriptor(
+ const MDNode *MD, TypeDescriptorsMapTy &TypeDescriptors,
+ TypeNameMapTy &TypeNames, Module &M) {
+ if (MD->getNumOperands() < 1)
+ return false;
+
+ MDString *NameNode = dyn_cast<MDString>(MD->getOperand(0));
+ if (!NameNode)
+ return false;
+
+ std::string Name = NameNode->getString().str();
+ if (Name.empty())
+ Name = getAnonymousStructIdentifier(MD, TypeNames);
+ if (Name.empty())
+ return false;
+ TypeNames[MD] = Name;
+ std::string EncodedName = encodeName(Name);
+
+ GlobalVariable *GV =
+ dyn_cast_or_null<GlobalVariable>(M.getNamedValue(EncodedName));
+ if (GV) {
+ TypeDescriptors[MD] = GV;
+ return true;
+ }
+
+ SmallVector<std::pair<Constant *, uint64_t>> Members;
+ for (int i = 1, e = MD->getNumOperands(); i < e; i += 2) {
+ const MDNode *MemberNode = dyn_cast<MDNode>(MD->getOperand(i));
+ if (!MemberNode)
+ return false;
+
+ Constant *Member;
+ auto TDI = TypeDescriptors.find(MemberNode);
+ if (TDI != TypeDescriptors.end()) {
+ Member = TDI->second;
+ } else {
+ if (!generateBaseTypeDescriptor(MemberNode, TypeDescriptors, TypeNames,
+ M))
+ return false;
+
+ Member = TypeDescriptors[MemberNode];
+ }
+
+ uint64_t Offset =
+ mdconst::extract<ConstantInt>(MD->getOperand(i + 1))->getZExtValue();
+
+ Members.push_back(std::make_pair(Member, Offset));
+ }
+
+ // The descriptor for a scalar is:
+ // [2, member count, [type pointer, offset]..., name]
+
+ LLVMContext &C = MD->getContext();
+ Constant *NameData = ConstantDataArray::getString(C, NameNode->getString());
+ SmallVector<Type *> TDSubTys;
+ SmallVector<Constant *> TDSubData;
+
+ TDSubTys.push_back(IntptrTy);
+ TDSubData.push_back(ConstantInt::get(IntptrTy, 2));
+
+ TDSubTys.push_back(IntptrTy);
+ TDSubData.push_back(ConstantInt::get(IntptrTy, Members.size()));
+
+ bool ShouldBeComdat = !isAnonymousNamespaceName(NameNode->getString());
+ for (auto &Member : Members) {
+ TDSubTys.push_back(Member.first->getType());
+ TDSubData.push_back(Member.first);
+
+ TDSubTys.push_back(IntptrTy);
+ TDSubData.push_back(ConstantInt::get(IntptrTy, Member.second));
+ }
+
+ TDSubTys.push_back(NameData->getType());
+ TDSubData.push_back(NameData);
+
+ StructType *TDTy = StructType::get(C, TDSubTys);
+ Constant *TD = ConstantStruct::get(TDTy, TDSubData);
+
+ GlobalVariable *TDGV =
+ new GlobalVariable(TDTy, true,
+ !ShouldBeComdat ? GlobalValue::InternalLinkage
+ : GlobalValue::LinkOnceODRLinkage,
+ TD, EncodedName);
+ M.insertGlobalVariable(TDGV);
+
+ if (ShouldBeComdat) {
+ if (TargetTriple.isOSBinFormatELF()) {
+ Comdat *TDComdat = M.getOrInsertComdat(EncodedName);
+ TDGV->setComdat(TDComdat);
+ }
+ appendToUsed(M, TDGV);
+ }
+
+ TypeDescriptors[MD] = TDGV;
+ return true;
+}
+
+bool TypeSanitizer::generateTypeDescriptor(
+ const MDNode *MD, TypeDescriptorsMapTy &TypeDescriptors,
+ TypeNameMapTy &TypeNames, Module &M) {
+ // Here we need to generate a type descriptor corresponding to this TBAA
+ // metadata node. Under the current scheme there are three kinds of TBAA
+ // metadata nodes: scalar nodes, struct nodes, and struct tag nodes.
+
+ if (MD->getNumOperands() < 3)
+ return false;
+
+ const MDNode *BaseNode = dyn_cast<MDNode>(MD->getOperand(0));
+ if (!BaseNode)
+ return false;
+
+ // This is a struct tag (element-access) node.
+
+ const MDNode *AccessNode = dyn_cast<MDNode>(MD->getOperand(1));
+ if (!AccessNode)
+ return false;
+
+ Constant *Base;
+ auto TDI = TypeDescriptors.find(BaseNode);
+ if (TDI != TypeDescriptors.end()) {
+ Base = TDI->second;
+ } else {
+ if (!generateBaseTypeDescriptor(BaseNode, TypeDescriptors, TypeNames, M))
+ return false;
+
+ Base = TypeDescriptors[BaseNode];
+ }
+
+ Constant *Access;
+ TDI = TypeDescriptors.find(AccessNode);
+ if (TDI != TypeDescriptors.end()) {
+ Access = TDI->second;
+ } else {
+ if (!generateBaseTypeDescriptor(AccessNode, TypeDescriptors, TypeNames, M))
+ return false;
+
+ Access = TypeDescriptors[AccessNode];
+ }
+
+ uint64_t Offset =
+ mdconst::extract<ConstantInt>(MD->getOperand(2))->getZExtValue();
+ std::string EncodedName =
+ std::string(Base->getName()) + "_o_" + utostr(Offset);
+
+ GlobalVariable *GV =
+ dyn_cast_or_null<GlobalVariable>(M.getNamedValue(EncodedName));
+ if (GV) {
+ TypeDescriptors[MD] = GV;
+ return true;
+ }
+
+ // The descriptor for a scalar is:
+ // [1, base-type pointer, access-type pointer, offset]
+
+ StructType *TDTy =
+ StructType::get(IntptrTy, Base->getType(), Access->getType(), IntptrTy);
+ Constant *TD =
+ ConstantStruct::get(TDTy, ConstantInt::get(IntptrTy, 1), Base, Access,
+ ConstantInt::get(IntptrTy, Offset));
+
+ bool ShouldBeComdat = cast<GlobalVariable>(Base)->getLinkage() ==
+ GlobalValue::LinkOnceODRLinkage;
+
+ GlobalVariable *TDGV =
+ new GlobalVariable(TDTy, true,
+ !ShouldBeComdat ? GlobalValue::InternalLinkage
+ : GlobalValue::LinkOnceODRLinkage,
+ TD, EncodedName);
+ M.insertGlobalVariable(TDGV);
+
+ if (ShouldBeComdat) {
+ if (TargetTriple.isOSBinFormatELF()) {
+ Comdat *TDComdat = M.getOrInsertComdat(EncodedName);
+ TDGV->setComdat(TDComdat);
+ }
+ appendToUsed(M, TDGV);
+ }
+
+ TypeDescriptors[MD] = TDGV;
+ return true;
+}
+
+Value *TypeSanitizer::getShadowBase(Function &F) {
+ IRBuilder<> IRB(&F.front().front());
+ Constant *GlobalShadowAddress =
+ F.getParent()->getOrInsertGlobal(kTysanShadowMemoryAddress, IntptrTy);
+ return IRB.CreateLoad(IntptrTy, GlobalShadowAddress, "shadow.base");
+}
+
+Value *TypeSanitizer::getAppMemMask(Function &F) {
+ IRBuilder<> IRB(&F.front().front());
+ Value *GlobalAppMemMask =
+ F.getParent()->getOrInsertGlobal(kTysanAppMemMask, IntptrTy);
+ return IRB.CreateLoad(IntptrTy, GlobalAppMemMask, "app.mem.mask");
+}
+
+bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) {
+ // This is required to prevent instrumenting call to __tysan_init from within
+ // the module constructor.
+ if (&F == TysanCtorFunction || &F == TysanGlobalsSetTypeFunction)
+ return false;
+ initializeCallbacks(*F.getParent());
+
+ SmallVector<std::pair<Instruction *, MemoryLocation>> MemoryAccesses;
+ SmallSetVector<const MDNode *, 8> TBAAMetadata;
+ SmallVector<Value *> MemTypeResetInsts;
+
+ bool Res = false;
+ bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeType);
+ const DataLayout &DL = F.getParent()->getDataLayout();
+ // Traverse all instructions, collect loads/stores/returns, check for calls.
+ for (auto &BB : F) {
+ for (auto &Inst : BB) {
+ // Skip memory accesses inserted by another instrumentation.
+ if (Inst.getMetadata(LLVMContext::MD_nosanitize))
+ continue;
+
+ if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst) ||
+ isa<AtomicCmpXchgInst>(Inst) || isa<AtomicRMWInst>(Inst)) {
+ MemoryLocation MLoc = MemoryLocation::get(&Inst);
+
+ // Swift errors are special (we can't introduce extra uses on them).
+ if (MLoc.Ptr->isSwiftError())
+ continue;
+
+ // Skip non-address-space-0 pointers; we don't know how to handle them.
+ Type *PtrTy = cast<PointerType>(MLoc.Ptr->getType());
+ if (PtrTy->getPointerAddressSpace() != 0)
+ continue;
+
+ if (MLoc.AATags.TBAA)
+ TBAAMetadata.insert(MLoc.AATags.TBAA);
+ MemoryAccesses.push_back(std::make_pair(&Inst, MLoc));
+ } else if (isa<CallInst>(Inst) || isa<InvokeInst>(Inst)) {
+ if (CallInst *CI = dyn_cast<CallInst>(&Inst))
+ maybeMarkSanitizerLibraryCallNoBuiltin(CI, &TLI);
+
+ if (isa<MemIntrinsic>(Inst)) {
+ MemTypeResetInsts.push_back(&Inst);
+ } else if (auto *II = dyn_cast<IntrinsicInst>(&Inst)) {
+ if (II->getIntrinsicID() == Intrinsic::lifetime_start ||
+ II->getIntrinsicID() == Intrinsic::lifetime_end)
+ MemTypeResetInsts.push_back(&Inst);
+ }
+ } else if (isa<AllocaInst>(Inst)) {
+ MemTypeResetInsts.push_back(&Inst);
+ }
+ }
+ }
+
+ // byval arguments also need their types reset (they're new stack memory,
+ // just like allocas).
+ for (auto &A : F.args())
+ if (A.hasByValAttr())
+ MemTypeResetInsts.push_back(&A);
+
+ // We have collected all loads and stores, and know for what TBAA nodes we
+ // need to generate type descriptors.
+
+ Module &M = *F.getParent();
+ TypeDescriptorsMapTy TypeDescriptors;
+ TypeNameMapTy TypeNames;
+ for (const MDNode *MD : TBAAMetadata) {
+ if (TypeDescriptors.count(MD))
+ continue;
+
+ if (!generateTypeDescriptor(MD, TypeDescriptors, TypeNames, M))
+ return Res; // Giving up.
+
+ Res = true;
+ }
+
+ Value *ShadowBase = nullptr, *AppMemMask = nullptr;
+ for (auto &MA : MemoryAccesses)
+ Res |= instrumentMemoryAccess(MA.first, MA.second, ShadowBase, AppMemMask,
+ SanitizeFunction, TypeDescriptors, DL);
+
+ for (auto Inst : MemTypeResetInsts)
+ Res |= instrumentMemInst(Inst, ShadowBase, AppMemMask, DL);
+
+ return Res;
+}
+
+static Value *ConvertToShadowDataInt(IRBuilder<> &IRB, Value *Ptr,
+ Type *IntptrTy, uint64_t PtrShift,
+ Value *ShadowBase, Value *AppMemMask) {
+ return IRB.CreateAdd(
+ IRB.CreateShl(
+ IRB.CreateAnd(IRB.CreatePtrToInt(Ptr, IntptrTy, "app.ptr.int"),
+ AppMemMask, "app.ptr.masked"),
+ PtrShift, "app.ptr.shifted"),
+ ShadowBase, "shadow.ptr.int");
+}
+
+bool TypeSanitizer::instrumentWithShadowUpdate(
+ IRBuilder<> &IRB, const MDNode *TBAAMD, Value *Ptr, uint64_t AccessSize,
+ bool IsRead, bool IsWrite, Value *&ShadowBase, Value *&AppMemMask,
+ bool ForceSetType, bool SanitizeFunction,
+ TypeDescriptorsMapTy &TypeDescriptors, const DataLayout &DL) {
+ if (!ShadowBase)
+ ShadowBase = getShadowBase(*IRB.GetInsertBlock()->getParent());
+ if (!AppMemMask)
+ AppMemMask = getAppMemMask(*IRB.GetInsertBlock()->getParent());
+
+ Constant *TDGV;
+ if (TBAAMD)
+ TDGV = TypeDescriptors[TBAAMD];
+ else
+ TDGV = Constant::getNullValue(IRB.getPtrTy());
+
+ Value *TD = IRB.CreateBitCast(TDGV, IRB.getPtrTy());
+
+ Value *ShadowDataInt = ConvertToShadowDataInt(IRB, Ptr, IntptrTy, PtrShift,
+ ShadowBase, AppMemMask);
+ Type *Int8PtrPtrTy = IRB.getPtrTy()->getPointerTo();
+ Value *ShadowData =
+ IRB.CreateIntToPtr(ShadowDataInt, Int8PtrPtrTy, "shadow.ptr");
+
+ auto SetType = [&]() {
+ IRB.CreateStore(TD, ShadowData);
+
+ // Now fill the remainder of the shadow memory corresponding to the
+ // remainder of the the bytes of the type with a bad type descriptor.
+ for (uint64_t i = 1; i < AccessSize; ++i) {
+ Value *BadShadowData = IRB.CreateIntToPtr(
+ IRB.CreateAdd(ShadowDataInt,
+ ConstantInt::get(IntptrTy, i << PtrShift),
+ "shadow.byte." + Twine(i) + ".offset"),
+ Int8PtrPtrTy, "shadow.byte." + Twine(i) + ".ptr");
+
+ // This is the TD value, -i, which is used to indicate that the byte is
+ // i bytes after the first byte of the type.
+ Value *BadTD =
+ IRB.CreateIntToPtr(ConstantInt::getSigned(IntptrTy, -i),
+ IRB.getPtrTy(), "bad.descriptor" + Twine(i));
+ IRB.CreateStore(BadTD, BadShadowData);
+ }
+ };
+
+ if (!ForceSetType && (!ClWritesAlwaysSetType || IsRead)) {
+ // We need to check the type here. If the type is unknown, then the read
+ // sets the type. If the type is known, then it is checked. If the type
+ // doesn't match, then we call the runtime (which may yet determine that
+ // the mismatch is okay).
+ LLVMContext &C = IRB.getContext();
+ MDNode *UnlikelyBW = MDBuilder(C).createBranchWeights(1, 100000);
+
+ Constant *Flags =
+ ConstantInt::get(OrdTy, (int)IsRead | (((int)IsWrite) << 1));
+
+ Value *LoadedTD =
+ IRB.CreateLoad(IRB.getPtrTy(), ShadowData, "shadow.desc");
+ if (SanitizeFunction) {
+ Value *BadTDCmp = IRB.CreateICmpNE(LoadedTD, TD, "bad.desc");
+ Instruction *BadTDTerm, *GoodTDTerm;
+ SplitBlockAndInsertIfThenElse(BadTDCmp, &*IRB.GetInsertPoint(),
+ &BadTDTerm, &GoodTDTerm, UnlikelyBW);
+ IRB.SetInsertPoint(BadTDTerm);
+
+ // We now know that the types did not match (we're on the slow path). If
+ // the type is unknown, then set it.
+ Value *NullTDCmp = IRB.CreateIsNull(LoadedTD);
+ Instruction *NullTDTerm, *MismatchTerm;
+ SplitBlockAndInsertIfThenElse(NullTDCmp, &*IRB.GetInsertPoint(),
+ &NullTDTerm, &MismatchTerm);
+
+ // If the type is unknown, then set the type.
+ IRB.SetInsertPoint(NullTDTerm);
+
+ // We're about to set the type. Make sure that all bytes in the value are
+ // also of unknown type.
+ Value *Size = ConstantInt::get(OrdTy, AccessSize);
+ Value *NotAllUnkTD = IRB.getFalse();
+ for (uint64_t i = 1; i < AccessSize; ++i) {
+ Value *UnkShadowData = IRB.CreateIntToPtr(
+ IRB.CreateAdd(ShadowDataInt,
+ ConstantInt::get(IntptrTy, i << PtrShift)),
+ Int8PtrPtrTy);
+ Value *ILdTD = IRB.CreateLoad(IRB.getPtrTy(), UnkShadowData);
+ NotAllUnkTD = IRB.CreateOr(NotAllUnkTD, IRB.CreateIsNotNull(ILdTD));
+ }
+
+ Instruction *BeforeSetType = &*IRB.GetInsertPoint();
+ Instruction *BadUTDTerm = SplitBlockAndInsertIfThen(
+ NotAllUnkTD, BeforeSetType, false, UnlikelyBW);
+ IRB.SetInsertPoint(BadUTDTerm);
+ IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()),
+ Size, (Value *)TD, (Value *)Flags});
+
+ IRB.SetInsertPoint(BeforeSetType);
+ SetType();
+
+ // We have a non-trivial mismatch. Call the runtime.
+ IRB.SetInsertPoint(MismatchTerm);
+ IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()),
+ Size, (Value *)TD, (Value *)Flags});
+
+ // We appear to have the right type. Make sure that all other bytes in
+ // the type are still marked as interior bytes. If not, call the runtime.
+ IRB.SetInsertPoint(GoodTDTerm);
+ Value *NotAllBadTD = IRB.getFalse();
+ for (uint64_t i = 1; i < AccessSize; ++i) {
+ Value *BadShadowData = IRB.CreateIntToPtr(
+ IRB.CreateAdd(ShadowDataInt,
+ ConstantInt::get(IntptrTy, i << PtrShift)),
+ Int8PtrPtrTy);
+ Value *ILdTD = IRB.CreatePtrToInt(
+ IRB.CreateLoad(IRB.getPtrTy(), BadShadowData), IntptrTy);
+ NotAllBadTD = IRB.CreateOr(
+ NotAllBadTD,
+ IRB.CreateICmpSGE(ILdTD, ConstantInt::get(IntptrTy, 0)));
+ }
+
+ Instruction *BadITDTerm = SplitBlockAndInsertIfThen(
+ NotAllBadTD, &*IRB.GetInsertPoint(), false, UnlikelyBW);
+ IRB.SetInsertPoint(BadITDTerm);
+ IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()),
+ Size, (Value *)TD, (Value *)Flags});
+ } else {
+ // If we're not sanitizing this function, then we only care whether we
+ // need to *set* the type.
+ Value *NullTDCmp = IRB.CreateIsNull(LoadedTD, "desc.set");
+ Instruction *NullTDTerm = SplitBlockAndInsertIfThen(
+ NullTDCmp, &*IRB.GetInsertPoint(), false, UnlikelyBW);
+ IRB.SetInsertPoint(NullTDTerm);
+ NullTDTerm->getParent()->setName("set.type");
+ SetType();
+ }
+ } else if (ForceSetType || IsWrite) {
+ // In the mode where writes always set the type, for a write (which does
+ // not also read), we just set the type.
+ SetType();
+ }
+
+ return true;
+}
+
+bool TypeSanitizer::instrumentMemoryAccess(
+ Instruction *I, MemoryLocation &MLoc, Value *&ShadowBase,
+ Value *&AppMemMask, bool SanitizeFunction,
+ TypeDescriptorsMapTy &TypeDescriptors, const DataLayout &DL) {
+ IRBuilder<> IRB(I);
+ assert(MLoc.Size.isPrecise());
+ if (instrumentWithShadowUpdate(
+ IRB, MLoc.AATags.TBAA, const_cast<Value *>(MLoc.Ptr),
+ MLoc.Size.getValue(), I->mayReadFromMemory(), I->mayWriteToMemory(),
+ ShadowBase, AppMemMask, false, SanitizeFunction, TypeDescriptors,
+ DL)) {
+ ++NumInstrumentedAccesses;
+ return true;
+ }
+
+ return false;
+}
+
+// Memory-related intrinsics/instructions reset the type of the destination
+// memory (including allocas and byval arguments).
+bool TypeSanitizer::instrumentMemInst(Value *V, Value *&ShadowBase,
+ Value *&AppMemMask,
+ const DataLayout &DL) {
+ BasicBlock::iterator IP;
+ BasicBlock *BB;
+ Function *F;
+
+ if (auto *I = dyn_cast<Instruction>(V)) {
+ IP = BasicBlock::iterator(I);
+ BB = I->getParent();
+ F = BB->getParent();
+ } else {
+ auto *A = cast<Argument>(V);
+ F = A->getParent();
+ BB = &F->getEntryBlock();
+ IP = BB->getFirstInsertionPt();
+
+ if (auto *I = cast_or_null<Instruction>(ShadowBase)) {
+ if (IP->comesBefore(I))
+ IP = I->getNextNode()->getIterator();
+ }
+ if (auto *I = cast_or_null<Instruction>(AppMemMask)) {
+ if (IP->comesBefore(I))
+ IP = I->getNextNode()->getIterator();
+ }
+ }
+
+ Value *Dest, *Size, *Src = nullptr;
+ bool NeedsMemMove = false;
+ IRBuilder<> IRB(BB, IP);
+
+ if (auto *A = dyn_cast<Argument>(V)) {
+ assert(A->hasByValAttr() && "Type reset for non-byval argument?");
+
+ Dest = A;
+ Size =
+ ConstantInt::get(IntptrTy, DL.getTypeAllocSize(A->getParamByValType()));
+ } else {
+ auto *I = cast<Instruction>(V);
+ if (auto *MI = dyn_cast<MemIntrinsic>(I)) {
+ if (MI->getDestAddressSpace() != 0)
+ return false;
+
+ Dest = MI->getDest();
+ Size = MI->getLength();
+
+ if (auto *MTI = dyn_cast<MemTransferInst>(MI)) {
+ if (MTI->getSourceAddressSpace() == 0) {
+ Src = MTI->getSource();
+ NeedsMemMove = isa<MemMoveInst>(MTI);
+ }
+ }
+ } else if (auto *II = dyn_cast<IntrinsicInst>(I)) {
+ if (II->getIntrinsicID() != Intrinsic::lifetime_start &&
+ II->getIntrinsicID() != Intrinsic::lifetime_end)
+ return false;
+
+ Size = II->getArgOperand(0);
+ Dest = II->getArgOperand(1);
+ } else if (auto *AI = dyn_cast<AllocaInst>(I)) {
+ // We need to clear the types for new stack allocations (or else we might
+ // read stale type information from a previous function execution).
+
+ IRB.SetInsertPoint(&*std::next(BasicBlock::iterator(I)));
+ IRB.SetInstDebugLocation(I);
+
+ Size = IRB.CreateMul(
+ IRB.CreateZExtOrTrunc(AI->getArraySize(), IntptrTy),
+ ConstantInt::get(IntptrTy,
+ DL.getTypeAllocSize(AI->getAllocatedType())));
+ Dest = I;
+ } else {
+ return false;
+ }
+ }
+
+ if (!ShadowBase)
+ ShadowBase = getShadowBase(*F);
+ if (!AppMemMask)
+ AppMemMask = getAppMemMask(*F);
+
+ Value *ShadowDataInt = IRB.CreateAdd(
+ IRB.CreateShl(
+ IRB.CreateAnd(IRB.CreatePtrToInt(Dest, IntptrTy), AppMemMask),
+ PtrShift),
+ ShadowBase);
+ Value *ShadowData = IRB.CreateIntToPtr(ShadowDataInt, IRB.getPtrTy());
+
+ if (!Src) {
+ IRB.CreateMemSet(ShadowData, IRB.getInt8(0), IRB.CreateShl(Size, PtrShift),
+ Align(1u << PtrShift));
+ return true;
+ }
+
+ Value *SrcShadowDataInt = IRB.CreateAdd(
+ IRB.CreateShl(
+ IRB.CreateAnd(IRB.CreatePtrToInt(Src, IntptrTy), AppMemMask),
+ PtrShift),
+ ShadowBase);
+ Value *SrcShadowData =
+ IRB.CreateIntToPtr(SrcShadowDataInt, IRB.getPtrTy());
+
+ if (NeedsMemMove) {
+ IRB.CreateMemMove(ShadowData, Align(1u << PtrShift), SrcShadowData,
+ Align(1u << PtrShift), IRB.CreateShl(Size, PtrShift));
+ } else {
+ IRB.CreateMemCpy(ShadowData, Align(1u << PtrShift), SrcShadowData,
+ Align(1u << PtrShift), IRB.CreateShl(Size, PtrShift));
+ }
+
+ return true;
+}
+
+PreservedAnalyses TypeSanitizerPass::run(Function &F,
+ FunctionAnalysisManager &FAM) {
+ TypeSanitizer TySan(*F.getParent());
+ TySan.run(F, FAM.getResult<TargetLibraryAnalysis>(F));
+ return PreservedAnalyses::none();
+}
+
+PreservedAnalyses ModuleTypeSanitizerPass::run(Module &M,
+ ModuleAnalysisManager &AM) {
+ insertModuleCtor(M);
+ return PreservedAnalyses::none();
+}
diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
index f5abed0dd51786..9e60690009dcf6 100644
--- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -955,6 +955,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
case Attribute::SanitizeAddress:
case Attribute::SanitizeMemory:
case Attribute::SanitizeThread:
+ case Attribute::SanitizeType:
case Attribute::SanitizeHWAddress:
case Attribute::SanitizeMemTag:
case Attribute::SpeculativeLoadHardening:
diff --git a/llvm/test/Instrumentation/TypeSanitizer/access-with-offfset.ll b/llvm/test/Instrumentation/TypeSanitizer/access-with-offfset.ll
new file mode 100644
index 00000000000000..297ee83527b5c1
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/access-with-offfset.ll
@@ -0,0 +1,71 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+;.
+; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2FC_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [18 x i8] } { i64 2, i64 0, [18 x i8] c"Simple C/C++ TBAA\00" }, comdat
+; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2fC_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat
+; CHECK: @[[__TYSAN_V1_ANY_20POINTER:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [12 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [12 x i8] c"any pointer\00" }, comdat
+; CHECK: @[[__TYSAN_V1_ANY_20POINTER_O_0:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_any_20pointer, ptr @__tysan_v1_any_20pointer, i64 0 }, comdat
+; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [5 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2fC_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_any_20pointer, ptr @__tysan_v1_any_20pointer_o_0], section "llvm.metadata"
+; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+;.
+define ptr @test_load_offset(ptr %argv) {
+; CHECK-LABEL: @test_load_offset(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 4
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 4
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 0, [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[DESC_SET:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[DESC_SET]], label [[SET_TYPE:%.*]], label [[TMP0:%.*]], !prof [[PROF0:![0-9]+]]
+; CHECK: set.type:
+; CHECK-NEXT: store ptr @__tysan_v1_any_20pointer_o_0, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_4_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 32
+; CHECK-NEXT: [[SHADOW_BYTE_4_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_4_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -4 to ptr), ptr [[SHADOW_BYTE_4_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_5_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 40
+; CHECK-NEXT: [[SHADOW_BYTE_5_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_5_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -5 to ptr), ptr [[SHADOW_BYTE_5_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_6_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 48
+; CHECK-NEXT: [[SHADOW_BYTE_6_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_6_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -6 to ptr), ptr [[SHADOW_BYTE_6_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_7_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 56
+; CHECK-NEXT: [[SHADOW_BYTE_7_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_7_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -7 to ptr), ptr [[SHADOW_BYTE_7_PTR]], align 8
+; CHECK-NEXT: br label [[TMP0]]
+; CHECK: 0:
+; CHECK-NEXT: [[L:%.*]] = load ptr, ptr null, align 8, !tbaa [[TBAA1:![0-9]+]]
+; CHECK-NEXT: ret ptr [[L]]
+;
+entry:
+ %l = load ptr, ptr null, align 8, !tbaa !0
+ ret ptr %l
+}
+
+!0 = !{!1, !1, i64 0}
+!1 = !{!"any pointer", !2, i64 0}
+!2 = !{!"omnipotent char", !3, i64 0}
+!3 = !{!"Simple C/C++ TBAA"}
+;.
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind }
+;.
+; CHECK: [[PROF0]] = !{!"branch_weights", i32 1, i32 100000}
+; CHECK: [[TBAA1]] = !{!2, !2, i64 0}
+; CHECK: [[META2:![0-9]+]] = !{!"any pointer", !3, i64 0}
+; CHECK: [[META3:![0-9]+]] = !{!"omnipotent char", !4, i64 0}
+; CHECK: [[META4:![0-9]+]] = !{!"Simple C/C++ TBAA"}
+;.
diff --git a/llvm/test/Instrumentation/TypeSanitizer/alloca.ll b/llvm/test/Instrumentation/TypeSanitizer/alloca.ll
new file mode 100644
index 00000000000000..94098bd8a1739a
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/alloca.ll
@@ -0,0 +1,29 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test basic type sanitizer instrumentation.
+;
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+declare void @alloca_test_use(ptr)
+
+define void @alloca_test() sanitize_type {
+; CHECK-LABEL: @alloca_test(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[X:%.*]] = alloca [10 x i8], align 1
+; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[X]] to i64
+; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[TMP4]], i8 0, i64 80, i1 false)
+; CHECK-NEXT: call void @alloca_test_use(ptr [[X]])
+; CHECK-NEXT: ret void
+;
+entry:
+ %x = alloca [10 x i8], align 1
+ call void @alloca_test_use([10 x i8]* %x)
+ ret void
+}
diff --git a/llvm/test/Instrumentation/TypeSanitizer/anon.ll b/llvm/test/Instrumentation/TypeSanitizer/anon.ll
new file mode 100644
index 00000000000000..70f5dcefde64c1
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/anon.ll
@@ -0,0 +1,283 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
+; Test basic type sanitizer instrumentation.
+;
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat
+; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat
+; CHECK: @[[__TYSAN_V1_INT:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat
+; CHECK: @[[__TYSAN_V1___ZTSN12__GLOBAL____N__11ZE:[a-zA-Z0-9_$"\\.-]+]] = internal constant { i64, i64, ptr, i64, [23 x i8] } { i64 2, i64 1, ptr @__tysan_v1_int, i64 24, [23 x i8] c"_ZTSN12_GLOBAL__N_11zE\00" }
+; CHECK: @[[__TYSAN_V1___ZTSN12__GLOBAL____N__11ZE_O_24:[a-zA-Z0-9_$"\\.-]+]] = internal constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1___ZTSN12__GLOBAL____N__11zE, ptr @__tysan_v1_int, i64 24 }
+; CHECK: @[[__TYSAN_V1___ZTS1YIN12__GLOBAL____N__11ZEE:[a-zA-Z0-9_$"\\.-]+]] = internal constant { i64, i64, ptr, i64, [27 x i8] } { i64 2, i64 1, ptr @__tysan_v1_int, i64 24, [27 x i8] c"_ZTS1yIN12_GLOBAL__N_11zEE\00" }
+; CHECK: @[[__TYSAN_V1___ZTS1YIN12__GLOBAL____N__11ZEE_O_24:[a-zA-Z0-9_$"\\.-]+]] = internal constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE, ptr @__tysan_v1_int, i64 24 }
+; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[__TYSAN_V1_____ANONYMOUS__027D9E575C5D34CB5D60D6A1D6276F95:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [1 x i8] } { i64 2, i64 1, ptr @__tysan_v1_int, i64 24, [1 x i8] zeroinitializer }, comdat
+; CHECK: @[[__TYSAN_V1_____ANONYMOUS__027D9E575C5D34CB5D60D6A1D6276F95_O_24:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95, ptr @__tysan_v1_int, i64 24 }, comdat
+; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [6 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24], section "llvm.metadata"
+
+
+define void @test_anon_ns(ptr %a, ptr %b) sanitize_type {
+; CHECK-LABEL: @test_anon_ns(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], @__tysan_v1___ZTSN12__GLOBAL____N__11zE_o_24
+; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0:![0-9]+]]
+; CHECK: 0:
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]]
+; CHECK: 2:
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
+; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null
+; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]]
+; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr
+; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8
+; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null
+; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]]
+; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr
+; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8
+; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null
+; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]]
+; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]]
+; CHECK: 18:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTSN12__GLOBAL____N__11zE_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP19]]
+; CHECK: 19:
+; CHECK-NEXT: store ptr @__tysan_v1___ZTSN12__GLOBAL____N__11zE_o_24, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: br label [[TMP21:%.*]]
+; CHECK: 20:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTSN12__GLOBAL____N__11zE_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP21]]
+; CHECK: 21:
+; CHECK-NEXT: br label [[TMP43:%.*]]
+; CHECK: 22:
+; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr
+; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8
+; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64
+; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0
+; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]]
+; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr
+; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8
+; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64
+; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0
+; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]]
+; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr
+; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8
+; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64
+; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0
+; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]]
+; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]]
+; CHECK: 41:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTSN12__GLOBAL____N__11zE_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP42]]
+; CHECK: 42:
+; CHECK-NEXT: br label [[TMP43]]
+; CHECK: 43:
+; CHECK-NEXT: store i32 42, ptr [[A]], align 4, !tbaa [[TBAA1:![0-9]+]]
+; CHECK-NEXT: [[APP_PTR_INT1:%.*]] = ptrtoint ptr [[B:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED2:%.*]] = and i64 [[APP_PTR_INT1]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED3:%.*]] = shl i64 [[APP_PTR_MASKED2]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT4:%.*]] = add i64 [[APP_PTR_SHIFTED3]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR5:%.*]] = inttoptr i64 [[SHADOW_PTR_INT4]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC6:%.*]] = load ptr, ptr [[SHADOW_PTR5]], align 8
+; CHECK-NEXT: [[BAD_DESC7:%.*]] = icmp ne ptr [[SHADOW_DESC6]], @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE_o_24
+; CHECK-NEXT: br i1 [[BAD_DESC7]], label [[TMP44:%.*]], label [[TMP66:%.*]], !prof [[PROF0]]
+; CHECK: 44:
+; CHECK-NEXT: [[TMP45:%.*]] = icmp eq ptr [[SHADOW_DESC6]], null
+; CHECK-NEXT: br i1 [[TMP45]], label [[TMP46:%.*]], label [[TMP64:%.*]]
+; CHECK: 46:
+; CHECK-NEXT: [[TMP47:%.*]] = add i64 [[SHADOW_PTR_INT4]], 8
+; CHECK-NEXT: [[TMP48:%.*]] = inttoptr i64 [[TMP47]] to ptr
+; CHECK-NEXT: [[TMP49:%.*]] = load ptr, ptr [[TMP48]], align 8
+; CHECK-NEXT: [[TMP50:%.*]] = icmp ne ptr [[TMP49]], null
+; CHECK-NEXT: [[TMP51:%.*]] = or i1 false, [[TMP50]]
+; CHECK-NEXT: [[TMP52:%.*]] = add i64 [[SHADOW_PTR_INT4]], 16
+; CHECK-NEXT: [[TMP53:%.*]] = inttoptr i64 [[TMP52]] to ptr
+; CHECK-NEXT: [[TMP54:%.*]] = load ptr, ptr [[TMP53]], align 8
+; CHECK-NEXT: [[TMP55:%.*]] = icmp ne ptr [[TMP54]], null
+; CHECK-NEXT: [[TMP56:%.*]] = or i1 [[TMP51]], [[TMP55]]
+; CHECK-NEXT: [[TMP57:%.*]] = add i64 [[SHADOW_PTR_INT4]], 24
+; CHECK-NEXT: [[TMP58:%.*]] = inttoptr i64 [[TMP57]] to ptr
+; CHECK-NEXT: [[TMP59:%.*]] = load ptr, ptr [[TMP58]], align 8
+; CHECK-NEXT: [[TMP60:%.*]] = icmp ne ptr [[TMP59]], null
+; CHECK-NEXT: [[TMP61:%.*]] = or i1 [[TMP56]], [[TMP60]]
+; CHECK-NEXT: br i1 [[TMP61]], label [[TMP62:%.*]], label [[TMP63:%.*]], !prof [[PROF0]]
+; CHECK: 62:
+; CHECK-NEXT: call void @__tysan_check(ptr [[B]], i32 4, ptr @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP63]]
+; CHECK: 63:
+; CHECK-NEXT: store ptr @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE_o_24, ptr [[SHADOW_PTR5]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET8:%.*]] = add i64 [[SHADOW_PTR_INT4]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR9:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET8]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR9]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET10:%.*]] = add i64 [[SHADOW_PTR_INT4]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR11:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET10]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR11]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET12:%.*]] = add i64 [[SHADOW_PTR_INT4]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR13:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET12]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR13]], align 8
+; CHECK-NEXT: br label [[TMP65:%.*]]
+; CHECK: 64:
+; CHECK-NEXT: call void @__tysan_check(ptr [[B]], i32 4, ptr @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP65]]
+; CHECK: 65:
+; CHECK-NEXT: br label [[TMP87:%.*]]
+; CHECK: 66:
+; CHECK-NEXT: [[TMP67:%.*]] = add i64 [[SHADOW_PTR_INT4]], 8
+; CHECK-NEXT: [[TMP68:%.*]] = inttoptr i64 [[TMP67]] to ptr
+; CHECK-NEXT: [[TMP69:%.*]] = load ptr, ptr [[TMP68]], align 8
+; CHECK-NEXT: [[TMP70:%.*]] = ptrtoint ptr [[TMP69]] to i64
+; CHECK-NEXT: [[TMP71:%.*]] = icmp sge i64 [[TMP70]], 0
+; CHECK-NEXT: [[TMP72:%.*]] = or i1 false, [[TMP71]]
+; CHECK-NEXT: [[TMP73:%.*]] = add i64 [[SHADOW_PTR_INT4]], 16
+; CHECK-NEXT: [[TMP74:%.*]] = inttoptr i64 [[TMP73]] to ptr
+; CHECK-NEXT: [[TMP75:%.*]] = load ptr, ptr [[TMP74]], align 8
+; CHECK-NEXT: [[TMP76:%.*]] = ptrtoint ptr [[TMP75]] to i64
+; CHECK-NEXT: [[TMP77:%.*]] = icmp sge i64 [[TMP76]], 0
+; CHECK-NEXT: [[TMP78:%.*]] = or i1 [[TMP72]], [[TMP77]]
+; CHECK-NEXT: [[TMP79:%.*]] = add i64 [[SHADOW_PTR_INT4]], 24
+; CHECK-NEXT: [[TMP80:%.*]] = inttoptr i64 [[TMP79]] to ptr
+; CHECK-NEXT: [[TMP81:%.*]] = load ptr, ptr [[TMP80]], align 8
+; CHECK-NEXT: [[TMP82:%.*]] = ptrtoint ptr [[TMP81]] to i64
+; CHECK-NEXT: [[TMP83:%.*]] = icmp sge i64 [[TMP82]], 0
+; CHECK-NEXT: [[TMP84:%.*]] = or i1 [[TMP78]], [[TMP83]]
+; CHECK-NEXT: br i1 [[TMP84]], label [[TMP85:%.*]], label [[TMP86:%.*]], !prof [[PROF0]]
+; CHECK: 85:
+; CHECK-NEXT: call void @__tysan_check(ptr [[B]], i32 4, ptr @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP86]]
+; CHECK: 86:
+; CHECK-NEXT: br label [[TMP87]]
+; CHECK: 87:
+; CHECK-NEXT: store i32 43, ptr [[B]], align 4, !tbaa [[TBAA6:![0-9]+]]
+; CHECK-NEXT: ret void
+;
+entry:
+ store i32 42, ptr %a, align 4, !tbaa !8
+ store i32 43, ptr %b, align 4, !tbaa !10
+ ret void
+
+}
+
+define void @test_anon_type(ptr %a) sanitize_type {
+; CHECK-LABEL: @test_anon_type(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24
+; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0]]
+; CHECK: 0:
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]]
+; CHECK: 2:
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
+; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null
+; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]]
+; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr
+; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8
+; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null
+; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]]
+; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr
+; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8
+; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null
+; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]]
+; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]]
+; CHECK: 18:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP19]]
+; CHECK: 19:
+; CHECK-NEXT: store ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: br label [[TMP21:%.*]]
+; CHECK: 20:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP21]]
+; CHECK: 21:
+; CHECK-NEXT: br label [[TMP43:%.*]]
+; CHECK: 22:
+; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr
+; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8
+; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64
+; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0
+; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]]
+; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr
+; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8
+; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64
+; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0
+; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]]
+; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr
+; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8
+; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64
+; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0
+; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]]
+; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]]
+; CHECK: 41:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP42]]
+; CHECK: 42:
+; CHECK-NEXT: br label [[TMP43]]
+; CHECK: 43:
+; CHECK-NEXT: store i32 42, ptr [[A]], align 4, !tbaa [[TBAA8:![0-9]+]]
+; CHECK-NEXT: ret void
+;
+entry:
+ store i32 42, ptr %a, align 4, !tbaa !12
+ ret void
+
+}
+
+!0 = !{!"Simple C++ TBAA"}
+!1 = !{!"omnipotent char", !0, i64 0}
+!2 = !{!"int", !1, i64 0}
+!7 = !{!"_ZTSN12_GLOBAL__N_11zE", !2, i64 24}
+!8 = !{!7, !2, i64 24}
+!9 = !{!"_ZTS1yIN12_GLOBAL__N_11zEE", !2, i64 24}
+!10 = !{!9, !2, i64 24}
+!11 = !{!"", !2, i64 24}
+!12 = !{!11, !2, i64 24}
diff --git a/llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll b/llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll
new file mode 100644
index 00000000000000..7f25e36e6660e8
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll
@@ -0,0 +1,93 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs
+; Test basic type sanitizer instrumentation.
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat
+; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat
+; CHECK: @[[__TYSAN_V1_INT:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat
+; CHECK: @[[__TYSAN_V1_INT_O_0:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_int, ptr @__tysan_v1_int, i64 0 }, comdat
+; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [5 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int, ptr @__tysan_v1_int_o_0], section "llvm.metadata"
+; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+;
+define i32 @test_load_nsan(ptr %a) {
+; CHECK-LABEL: @test_load_nsan(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[DESC_SET:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[DESC_SET]], label [[SET_TYPE:%.*]], label [[TMP0:%.*]], !prof [[PROF0:![0-9]+]]
+; CHECK: set.type:
+; CHECK-NEXT: store ptr @__tysan_v1_int_o_0, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: br label [[TMP0]]
+; CHECK: 0:
+; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A]], align 4, !tbaa [[TBAA1:![0-9]+]]
+; CHECK-NEXT: ret i32 [[TMP1]]
+;
+entry:
+ %tmp1 = load i32, ptr %a, align 4, !tbaa !3
+ ret i32 %tmp1
+}
+
+define void @test_store_nsan(ptr %a) {
+; CHECK-LABEL: @test_store_nsan(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[DESC_SET:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[DESC_SET]], label [[SET_TYPE:%.*]], label [[TMP0:%.*]], !prof [[PROF0]]
+; CHECK: set.type:
+; CHECK-NEXT: store ptr @__tysan_v1_int_o_0, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: br label [[TMP0]]
+; CHECK: 0:
+; CHECK-NEXT: store i32 42, ptr [[A]], align 4, !tbaa [[TBAA1]]
+; CHECK-NEXT: ret void
+;
+entry:
+ store i32 42, ptr %a, align 4, !tbaa !3
+ ret void
+}
+
+; CHECK-LABEL: @tysan.module_ctor(
+; CHECK-NEXT: call void @__tysan_init()
+; CHECK-NEXT: ret void
+;
+; CHECK: [[PROF0]] = !{!"branch_weights", i32 1, i32 100000}
+
+!0 = !{!"Simple C++ TBAA"}
+!1 = !{!"omnipotent char", !0, i64 0}
+!2 = !{!"int", !1, i64 0}
+!3 = !{!2, !2, i64 0}
diff --git a/llvm/test/Instrumentation/TypeSanitizer/basic.ll b/llvm/test/Instrumentation/TypeSanitizer/basic.ll
new file mode 100644
index 00000000000000..132df722e83c25
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/basic.ll
@@ -0,0 +1,214 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
+; Test basic type sanitizer instrumentation.
+;
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+
+; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat
+; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat
+; CHECK: @[[__TYSAN_V1_INT:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat
+; CHECK: @[[__TYSAN_V1_INT_O_0:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_int, ptr @__tysan_v1_int, i64 0 }, comdat
+; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[__TYSAN_V1___ZTS1X:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, ptr, i64, [7 x i8] } { i64 2, i64 2, ptr @__tysan_v1_int, i64 0, ptr @__tysan_v1_int, i64 4, [7 x i8] c"_ZTS1x\00" }, comdat
+; CHECK: @[[__TYSAN_V1___ZTS1V:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, ptr, i64, ptr, i64, [7 x i8] } { i64 2, i64 3, ptr @__tysan_v1_int, i64 8, ptr @__tysan_v1_int, i64 12, ptr @__tysan_v1___ZTS1x, i64 16, [7 x i8] c"_ZTS1v\00" }, comdat
+; CHECK: @[[__TYSAN_V1___ZTS1V_O_12:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1___ZTS1v, ptr @__tysan_v1_int, i64 12 }, comdat
+; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [8 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int, ptr @__tysan_v1_int_o_0, ptr @__tysan_v1___ZTS1x, ptr @__tysan_v1___ZTS1v, ptr @__tysan_v1___ZTS1v_o_12], section "llvm.metadata"
+
+define i32 @test_load(ptr %a) sanitize_type {
+; CHECK-LABEL: @test_load(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], @__tysan_v1_int_o_0
+; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0:![0-9]+]]
+; CHECK: 0:
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]]
+; CHECK: 2:
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
+; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null
+; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]]
+; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr
+; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8
+; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null
+; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]]
+; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr
+; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8
+; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null
+; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]]
+; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]]
+; CHECK: 18:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_int_o_0, i32 1)
+; CHECK-NEXT: br label [[TMP19]]
+; CHECK: 19:
+; CHECK-NEXT: store ptr @__tysan_v1_int_o_0, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: br label [[TMP21:%.*]]
+; CHECK: 20:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_int_o_0, i32 1)
+; CHECK-NEXT: br label [[TMP21]]
+; CHECK: 21:
+; CHECK-NEXT: br label [[TMP43:%.*]]
+; CHECK: 22:
+; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr
+; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8
+; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64
+; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0
+; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]]
+; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr
+; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8
+; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64
+; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0
+; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]]
+; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr
+; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8
+; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64
+; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0
+; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]]
+; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]]
+; CHECK: 41:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_int_o_0, i32 1)
+; CHECK-NEXT: br label [[TMP42]]
+; CHECK: 42:
+; CHECK-NEXT: br label [[TMP43]]
+; CHECK: 43:
+; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A]], align 4, !tbaa [[TBAA1:![0-9]+]]
+; CHECK-NEXT: ret i32 [[TMP1]]
+;
+entry:
+ %tmp1 = load i32, ptr %a, align 4, !tbaa !3
+ ret i32 %tmp1
+}
+
+define void @test_store(ptr %a) sanitize_type {
+; CHECK-LABEL: @test_store(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], @__tysan_v1___ZTS1v_o_12
+; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0]]
+; CHECK: 0:
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]]
+; CHECK: 2:
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
+; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null
+; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]]
+; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr
+; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8
+; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null
+; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]]
+; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr
+; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8
+; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null
+; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]]
+; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]]
+; CHECK: 18:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTS1v_o_12, i32 2)
+; CHECK-NEXT: br label [[TMP19]]
+; CHECK: 19:
+; CHECK-NEXT: store ptr @__tysan_v1___ZTS1v_o_12, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: br label [[TMP21:%.*]]
+; CHECK: 20:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTS1v_o_12, i32 2)
+; CHECK-NEXT: br label [[TMP21]]
+; CHECK: 21:
+; CHECK-NEXT: br label [[TMP43:%.*]]
+; CHECK: 22:
+; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr
+; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8
+; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64
+; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0
+; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]]
+; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr
+; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8
+; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64
+; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0
+; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]]
+; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr
+; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8
+; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64
+; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0
+; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]]
+; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]]
+; CHECK: 41:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTS1v_o_12, i32 2)
+; CHECK-NEXT: br label [[TMP42]]
+; CHECK: 42:
+; CHECK-NEXT: br label [[TMP43]]
+; CHECK: 43:
+; CHECK-NEXT: store i32 42, ptr [[A]], align 4, !tbaa [[TBAA5:![0-9]+]]
+; CHECK-NEXT: ret void
+;
+entry:
+ store i32 42, ptr %a, align 4, !tbaa !6
+ ret void
+}
+
+!0 = !{!"Simple C++ TBAA"}
+!1 = !{!"omnipotent char", !0, i64 0}
+!2 = !{!"int", !1, i64 0}
+!3 = !{!2, !2, i64 0}
+!4 = !{!"_ZTS1x", !2, i64 0, !2, i64 4}
+!5 = !{!"_ZTS1v", !2, i64 8, !2, i64 12, !4, i64 16}
+!6 = !{!5, !2, i64 12}
+;.
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { sanitize_type }
+; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind }
+;.
+; CHECK: [[PROF0]] = !{!"branch_weights", i32 1, i32 100000}
+; CHECK: [[TBAA1]] = !{!2, !2, i64 0}
+; CHECK: [[META2:![0-9]+]] = !{!"int", !3, i64 0}
+; CHECK: [[META3:![0-9]+]] = !{!"omnipotent char", !4, i64 0}
+; CHECK: [[META4:![0-9]+]] = !{!"Simple C++ TBAA"}
+; CHECK: [[TBAA5]] = !{!6, !2, i64 12}
+; CHECK: [[META6:![0-9]+]] = !{!"_ZTS1v", !2, i64 8, !2, i64 12, !7, i64 16}
+; CHECK: [[META7:![0-9]+]] = !{!"_ZTS1x", !2, i64 0, !2, i64 4}
+;.
diff --git a/llvm/test/Instrumentation/TypeSanitizer/byval.ll b/llvm/test/Instrumentation/TypeSanitizer/byval.ll
new file mode 100644
index 00000000000000..68ab1327b225bd
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/byval.ll
@@ -0,0 +1,88 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs
+; Test basic type sanitizer instrumentation.
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+;.
+; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata"
+; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+;.
+
+%struct.s20 = type { i32, i32, [24 x i8] }
+define void @byval_test(ptr byval(%struct.s20) align 32 %x) sanitize_type {
+; CHECK-LABEL: @byval_test(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[X:%.*]] to i64
+; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[TMP4]], i8 0, i64 256, i1 false)
+; CHECK-NEXT: ret void
+;
+entry:
+ ret void
+; NOTE: Ideally, we'd get the type from the caller's copy of the data (instead
+; of setting it all to unknown).
+}
+
+%struct = type { ptr, ptr }
+
+define ptr @test_insert_point(ptr byval(%struct) %v) {
+; CHECK-LABEL: @test_insert_point(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[V:%.*]] to i64
+; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[TMP4]], i8 0, i64 128, i1 false)
+; CHECK-NEXT: [[NAME:%.*]] = getelementptr inbounds [[STRUCT:%.*]], ptr [[V]], i64 0, i32 1
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[NAME]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[DESC_SET:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[DESC_SET]], label [[SET_TYPE:%.*]], label [[TMP5:%.*]], !prof [[PROF0:![0-9]+]]
+; CHECK: set.type:
+; CHECK-NEXT: store ptr null, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_4_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 32
+; CHECK-NEXT: [[SHADOW_BYTE_4_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_4_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -4 to ptr), ptr [[SHADOW_BYTE_4_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_5_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 40
+; CHECK-NEXT: [[SHADOW_BYTE_5_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_5_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -5 to ptr), ptr [[SHADOW_BYTE_5_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_6_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 48
+; CHECK-NEXT: [[SHADOW_BYTE_6_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_6_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -6 to ptr), ptr [[SHADOW_BYTE_6_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_7_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 56
+; CHECK-NEXT: [[SHADOW_BYTE_7_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_7_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -7 to ptr), ptr [[SHADOW_BYTE_7_PTR]], align 8
+; CHECK-NEXT: br label [[TMP5]]
+; CHECK: 5:
+; CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr [[NAME]], align 8
+; CHECK-NEXT: ret ptr [[TMP6]]
+;
+entry:
+ %name = getelementptr inbounds %struct, ptr %v, i64 0, i32 1
+ %0 = load ptr, ptr %name, align 8
+ ret ptr %0
+}
diff --git a/llvm/test/Instrumentation/TypeSanitizer/globals.ll b/llvm/test/Instrumentation/TypeSanitizer/globals.ll
new file mode 100644
index 00000000000000..05d0fd348444db
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/globals.ll
@@ -0,0 +1,66 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+ at global1 = global i32 0, align 4
+ at global2 = global i32 0, align 4
+
+; CHECK: @[[GLOBAL1:[a-zA-Z0-9_$"\\.-]+]] = global i32 0, align 4
+; CHECK: @[[GLOBAL2:[a-zA-Z0-9_$"\\.-]+]] = global i32 0, align 4
+; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat
+; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat
+; CHECK: @[[__TYSAN_V1_INT:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat
+; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [4 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int], section "llvm.metadata"
+; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+;.
+; CHECK-LABEL: define internal void @tysan.module_ctor(
+; CHECK-NEXT: call void @__tysan_init()
+; CHECK-NEXT: call void @__tysan_set_globals_types()
+; CHECK-NEXT: ret void
+;
+;
+; CHECK-LABEL: define internal void @__tysan_set_globals_types(
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 ptrtoint (ptr @global1 to i64), [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: store ptr @__tysan_v1_int, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: [[APP_PTR_MASKED1:%.*]] = and i64 ptrtoint (ptr @global1 to i64), [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED2:%.*]] = shl i64 [[APP_PTR_MASKED1]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT3:%.*]] = add i64 [[APP_PTR_SHIFTED2]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR4:%.*]] = inttoptr i64 [[SHADOW_PTR_INT3]] to ptr
+; CHECK-NEXT: store ptr @__tysan_v1_int, ptr [[SHADOW_PTR4]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET5:%.*]] = add i64 [[SHADOW_PTR_INT3]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR6:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET5]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR6]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET7:%.*]] = add i64 [[SHADOW_PTR_INT3]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR8:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET7]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR8]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET9:%.*]] = add i64 [[SHADOW_PTR_INT3]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR10:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET9]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR10]], align 8
+; CHECK-NEXT: ret void
+
+
+
+!llvm.tysan.globals = !{!13, !14}
+
+!0 = !{!"Simple C++ TBAA"}
+!1 = !{!"omnipotent char", !0, i64 0}
+!2 = !{!"int", !1, i64 0}
+!13 = !{ptr @global1, !2}
+!14 = !{ptr @global1, !2}
diff --git a/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll b/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll
new file mode 100644
index 00000000000000..4527aa5cf2a015
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll
@@ -0,0 +1,25 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+!llvm.tysan.globals = !{!0}
+
+!0 = distinct !{ptr undef, !1}
+!1 = !{!"any pointer", !2, i64 0}
+!2 = !{!"omnipotent char", !3, i64 0}
+!3 = !{!"Simple C/C++ TBAA"}
+;.
+; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata"
+; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+;.
+; CHECK-LABEL: @tysan.module_ctor(
+; CHECK-NEXT: call void @__tysan_init()
+; CHECK-NEXT: ret void
+;
+;.
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind }
+;.
+; CHECK: [[META0:![0-9]+]] = distinct !{ptr undef, !1}
+; CHECK: [[META1:![0-9]+]] = !{!"any pointer", !2, i64 0}
+; CHECK: [[META2:![0-9]+]] = !{!"omnipotent char", !3, i64 0}
+; CHECK: [[META3:![0-9]+]] = !{!"Simple C/C++ TBAA"}
+;.
diff --git a/llvm/test/Instrumentation/TypeSanitizer/memintrinsics.ll b/llvm/test/Instrumentation/TypeSanitizer/memintrinsics.ll
new file mode 100644
index 00000000000000..26f7c186748cb6
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/memintrinsics.ll
@@ -0,0 +1,77 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test basic type sanitizer instrumentation.
+;
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+declare void @llvm.memset.p0.i64(ptr nocapture, i8, i64, i32, i1) nounwind
+declare void @llvm.memmove.p0.p0.i64(ptr nocapture, ptr nocapture readonly, i64, i32, i1) nounwind
+declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture readonly, i64, i32, i1) nounwind
+
+define void @test_memset(ptr %a, ptr %b) nounwind uwtable sanitize_type {
+; CHECK-LABEL: @test_memset(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[TMP4]], i8 0, i64 800, i1 false)
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 1 [[A]], i8 0, i64 100, i1 false)
+; CHECK-NEXT: ret void
+;
+ entry:
+ tail call void @llvm.memset.p0.i64(ptr %a, i8 0, i64 100, i32 1, i1 false)
+ ret void
+}
+
+define void @test_memmove(ptr %a, ptr %b) nounwind uwtable sanitize_type {
+; CHECK-LABEL: @test_memmove(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: [[TMP5:%.*]] = ptrtoint ptr [[B:%.*]] to i64
+; CHECK-NEXT: [[TMP6:%.*]] = and i64 [[TMP5]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[TMP7:%.*]] = shl i64 [[TMP6]], 3
+; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[TMP7]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr
+; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr align 8 [[TMP4]], ptr align 8 [[TMP9]], i64 800, i1 false)
+; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr align 1 [[A]], ptr align 1 [[B]], i64 100, i1 false)
+; CHECK-NEXT: ret void
+;
+ entry:
+ tail call void @llvm.memmove.p0.p0.i64(ptr %a, ptr %b, i64 100, i32 1, i1 false)
+ ret void
+}
+
+define void @test_memcpy(ptr %a, ptr %b) nounwind uwtable sanitize_type {
+; CHECK-LABEL: @test_memcpy(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: [[TMP5:%.*]] = ptrtoint ptr [[B:%.*]] to i64
+; CHECK-NEXT: [[TMP6:%.*]] = and i64 [[TMP5]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[TMP7:%.*]] = shl i64 [[TMP6]], 3
+; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[TMP7]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr
+; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[TMP4]], ptr align 8 [[TMP9]], i64 800, i1 false)
+; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[A]], ptr align 1 [[B]], i64 100, i1 false)
+; CHECK-NEXT: ret void
+;
+ entry:
+ tail call void @llvm.memcpy.p0.p0.i64(ptr %a, ptr %b, i64 100, i32 1, i1 false)
+ ret void
+}
diff --git a/llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll b/llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll
new file mode 100644
index 00000000000000..67e408439ec165
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll
@@ -0,0 +1,39 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
+; Test basic type sanitizer instrumentation.
+;
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+;.
+; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata"
+; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+;.
+define i32 @test_load(ptr %a) sanitize_type {
+; CHECK-LABEL: @test_load(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A:%.*]], align 4, !tbaa [[TBAA0:![0-9]+]], !nosanitize !4
+; CHECK-NEXT: ret i32 [[TMP1]]
+;
+entry:
+ %tmp1 = load i32, ptr %a, align 4, !tbaa !3, !nosanitize !{}
+ ret i32 %tmp1
+}
+
+!0 = !{!"Simple C++ TBAA"}
+!1 = !{!"omnipotent char", !0, i64 0}
+!2 = !{!"int", !1, i64 0}
+!3 = !{!2, !2, i64 0}
+!4 = !{!"_ZTS1x", !2, i64 0, !2, i64 4}
+!5 = !{!"_ZTS1v", !2, i64 8, !2, i64 12, !4, i64 16}
+!6 = !{!5, !2, i64 12}
+;.
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { sanitize_type }
+; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind }
+;.
+; CHECK: [[TBAA0]] = !{!1, !1, i64 0}
+; CHECK: [[META1:![0-9]+]] = !{!"int", !2, i64 0}
+; CHECK: [[META2:![0-9]+]] = !{!"omnipotent char", !3, i64 0}
+; CHECK: [[META3:![0-9]+]] = !{!"Simple C++ TBAA"}
+; CHECK: [[META4:![0-9]+]] = !{}
+;.
diff --git a/llvm/test/Instrumentation/TypeSanitizer/sanitize-no-tbaa.ll b/llvm/test/Instrumentation/TypeSanitizer/sanitize-no-tbaa.ll
new file mode 100644
index 00000000000000..3cb7b8365866b0
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/sanitize-no-tbaa.ll
@@ -0,0 +1,180 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test basic type sanitizer instrumentation.
+;
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @test_load_unk(ptr %a) sanitize_type {
+; CHECK-LABEL: @test_load_unk(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0:![0-9]+]]
+; CHECK: 0:
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]]
+; CHECK: 2:
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
+; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null
+; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]]
+; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr
+; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8
+; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null
+; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]]
+; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr
+; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8
+; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null
+; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]]
+; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]]
+; CHECK: 18:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 1)
+; CHECK-NEXT: br label [[TMP19]]
+; CHECK: 19:
+; CHECK-NEXT: store ptr null, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: br label [[TMP21:%.*]]
+; CHECK: 20:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 1)
+; CHECK-NEXT: br label [[TMP21]]
+; CHECK: 21:
+; CHECK-NEXT: br label [[TMP43:%.*]]
+; CHECK: 22:
+; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr
+; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8
+; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64
+; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0
+; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]]
+; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr
+; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8
+; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64
+; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0
+; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]]
+; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr
+; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8
+; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64
+; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0
+; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]]
+; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]]
+; CHECK: 41:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 1)
+; CHECK-NEXT: br label [[TMP42]]
+; CHECK: 42:
+; CHECK-NEXT: br label [[TMP43]]
+; CHECK: 43:
+; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A]], align 4
+; CHECK-NEXT: ret i32 [[TMP1]]
+;
+entry:
+ %tmp1 = load i32, ptr %a, align 4
+ ret i32 %tmp1
+}
+
+define void @test_store_unk(ptr %a) sanitize_type {
+; CHECK-LABEL: @test_store_unk(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0]]
+; CHECK: 0:
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]]
+; CHECK: 2:
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
+; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null
+; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]]
+; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr
+; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8
+; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null
+; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]]
+; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr
+; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8
+; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null
+; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]]
+; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]]
+; CHECK: 18:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 2)
+; CHECK-NEXT: br label [[TMP19]]
+; CHECK: 19:
+; CHECK-NEXT: store ptr null, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: br label [[TMP21:%.*]]
+; CHECK: 20:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 2)
+; CHECK-NEXT: br label [[TMP21]]
+; CHECK: 21:
+; CHECK-NEXT: br label [[TMP43:%.*]]
+; CHECK: 22:
+; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr
+; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8
+; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64
+; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0
+; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]]
+; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr
+; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8
+; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64
+; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0
+; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]]
+; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr
+; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8
+; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64
+; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0
+; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]]
+; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]]
+; CHECK: 41:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 2)
+; CHECK-NEXT: br label [[TMP42]]
+; CHECK: 42:
+; CHECK-NEXT: br label [[TMP43]]
+; CHECK: 43:
+; CHECK-NEXT: store i32 42, ptr [[A]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ store i32 42, ptr %a, align 4
+ ret void
+}
diff --git a/llvm/test/Instrumentation/TypeSanitizer/swifterror.ll b/llvm/test/Instrumentation/TypeSanitizer/swifterror.ll
new file mode 100644
index 00000000000000..5711fb4b839f4d
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/swifterror.ll
@@ -0,0 +1,24 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test basic type sanitizer instrumentation.
+;
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @test_swifterror(ptr swifterror) sanitize_type {
+; CHECK-LABEL: @test_swifterror(
+; CHECK-NEXT: [[SWIFTERROR_PTR_VALUE:%.*]] = load ptr, ptr [[TMP0:%.*]], align 8
+; CHECK-NEXT: ret void
+;
+ %swifterror_ptr_value = load ptr, ptr %0
+ ret void
+}
+
+define void @test_swifterror_2(ptr swifterror) sanitize_type {
+; CHECK-LABEL: @test_swifterror_2(
+; CHECK-NEXT: store ptr null, ptr [[TMP0:%.*]], align 8
+; CHECK-NEXT: ret void
+;
+ store ptr null, ptr %0
+ ret void
+}
>From fbaff4033ba060d1478c924ba736be407b4edb80 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 22 Dec 2023 19:18:34 +0000
Subject: [PATCH 2/4] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20ch?=
=?UTF-8?q?anges=20to=20main=20this=20commit=20is=20based=20on?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Created using spr 1.3.4
[skip ci]
---
clang/include/clang/Basic/Features.def | 1 +
clang/include/clang/Basic/Sanitizers.def | 3 +
clang/include/clang/Driver/SanitizerArgs.h | 1 +
clang/lib/CodeGen/BackendUtil.cpp | 6 +
clang/lib/CodeGen/CGDecl.cpp | 3 +-
clang/lib/CodeGen/CGDeclCXX.cpp | 4 +
clang/lib/CodeGen/CodeGenFunction.cpp | 2 +
clang/lib/CodeGen/CodeGenModule.cpp | 12 +-
clang/lib/CodeGen/CodeGenTBAA.cpp | 6 +-
clang/lib/CodeGen/SanitizerMetadata.cpp | 44 +-
clang/lib/CodeGen/SanitizerMetadata.h | 13 +-
clang/lib/Driver/SanitizerArgs.cpp | 15 +-
clang/lib/Driver/ToolChains/CommonArgs.cpp | 6 +-
clang/lib/Driver/ToolChains/Darwin.cpp | 5 +
clang/lib/Driver/ToolChains/Linux.cpp | 2 +
clang/test/CodeGen/sanitize-type-attr.cpp | 74 ++
clang/test/Driver/sanitizer-ld.c | 23 +
llvm/include/llvm/Bitcode/LLVMBitCodes.h | 1 +
llvm/include/llvm/IR/Attributes.td | 4 +
.../Instrumentation/TypeSanitizer.h | 38 +
llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp | 28 +-
llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 2 +
llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 2 +
llvm/lib/CodeGen/ShrinkWrap.cpp | 1 +
llvm/lib/Passes/PassBuilder.cpp | 1 +
llvm/lib/Passes/PassRegistry.def | 2 +
.../Transforms/Instrumentation/CMakeLists.txt | 1 +
.../Instrumentation/TypeSanitizer.cpp | 873 ++++++++++++++++++
llvm/lib/Transforms/Utils/CodeExtractor.cpp | 1 +
.../TypeSanitizer/access-with-offfset.ll | 71 ++
.../Instrumentation/TypeSanitizer/alloca.ll | 29 +
.../Instrumentation/TypeSanitizer/anon.ll | 283 ++++++
.../TypeSanitizer/basic-nosan.ll | 93 ++
.../Instrumentation/TypeSanitizer/basic.ll | 214 +++++
.../Instrumentation/TypeSanitizer/byval.ll | 88 ++
.../Instrumentation/TypeSanitizer/globals.ll | 66 ++
.../TypeSanitizer/invalid-metadata.ll | 25 +
.../TypeSanitizer/memintrinsics.ll | 77 ++
.../TypeSanitizer/nosanitize.ll | 39 +
.../TypeSanitizer/sanitize-no-tbaa.ll | 180 ++++
.../TypeSanitizer/swifterror.ll | 24 +
41 files changed, 2327 insertions(+), 36 deletions(-)
create mode 100644 clang/test/CodeGen/sanitize-type-attr.cpp
create mode 100644 llvm/include/llvm/Transforms/Instrumentation/TypeSanitizer.h
create mode 100644 llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/access-with-offfset.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/alloca.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/anon.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/basic.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/byval.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/globals.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/memintrinsics.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/sanitize-no-tbaa.ll
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/swifterror.ll
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 06efac0cf1abd7..6a1bc04963af68 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -98,6 +98,7 @@ FEATURE(nullability_nullable_result, true)
FEATURE(memory_sanitizer,
LangOpts.Sanitize.hasOneOf(SanitizerKind::Memory |
SanitizerKind::KernelMemory))
+FEATURE(type_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Type))
FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread))
FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow))
FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def
index c2137e3f61f645..a0f54d9e86327a 100644
--- a/clang/include/clang/Basic/Sanitizers.def
+++ b/clang/include/clang/Basic/Sanitizers.def
@@ -73,6 +73,9 @@ SANITIZER("fuzzer", Fuzzer)
// libFuzzer-required instrumentation, no linking.
SANITIZER("fuzzer-no-link", FuzzerNoLink)
+// TypeSanitizer
+SANITIZER("type", Type)
+
// ThreadSanitizer
SANITIZER("thread", Thread)
diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index 07070ec4fc0653..52b482a0e8a1a9 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -86,6 +86,7 @@ class SanitizerArgs {
bool needsHwasanAliasesRt() const {
return needsHwasanRt() && HwasanUseAliases;
}
+ bool needsTysanRt() const { return Sanitizers.has(SanitizerKind::Type); }
bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); }
bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); }
bool needsFuzzer() const { return Sanitizers.has(SanitizerKind::Fuzzer); }
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 480410db1021b7..d7c233b4da3ff5 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -79,6 +79,7 @@
#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
+#include "llvm/Transforms/Instrumentation/TypeSanitizer.h"
#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Scalar/EarlyCSE.h"
#include "llvm/Transforms/Scalar/GVN.h"
@@ -685,6 +686,11 @@ static void addSanitizers(const Triple &TargetTriple,
MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
}
+ if (LangOpts.Sanitize.has(SanitizerKind::Type)) {
+ MPM.addPass(ModuleTypeSanitizerPass());
+ MPM.addPass(createModuleToFunctionPassAdaptor(TypeSanitizerPass()));
+ }
+
auto ASanPass = [&](SanitizerMask Mask, bool CompileKernel) {
if (LangOpts.Sanitize.has(Mask)) {
bool UseGlobalGC = asanUseGlobalsGC(TargetTriple, CodeGenOpts);
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index a5da0aa2965a00..3f8e58db65fe1b 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -481,7 +481,8 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
LocalDeclMap.find(&D)->second = Address(castedAddr, elemTy, alignment);
CGM.setStaticLocalDeclAddress(&D, castedAddr);
- CGM.getSanitizerMetadata()->reportGlobal(var, D);
+ CGM.getSanitizerMetadata()->reportGlobalToASan(var, D);
+ CGM.getSanitizerMetadata()->reportGlobalToTySan(var, D);
// Emit global variable debug descriptor for static vars.
CGDebugInfo *DI = getDebugInfo();
diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index e08a1e5f42df20..08b3e06cb5a450 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -472,6 +472,10 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrCleanUpFunction(
!isInNoSanitizeList(SanitizerKind::MemtagStack, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeMemTag);
+ if (getLangOpts().Sanitize.has(SanitizerKind::Type) &&
+ !isInNoSanitizeList(SanitizerKind::Type, Fn, Loc))
+ Fn->addFnAttr(llvm::Attribute::SanitizeType);
+
if (getLangOpts().Sanitize.has(SanitizerKind::Thread) &&
!isInNoSanitizeList(SanitizerKind::Thread, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeThread);
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 2199d7b58fb96e..26825802fc3d93 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -790,6 +790,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
Fn->addFnAttr(llvm::Attribute::SanitizeMemTag);
if (SanOpts.has(SanitizerKind::Thread))
Fn->addFnAttr(llvm::Attribute::SanitizeThread);
+ if (SanOpts.has(SanitizerKind::Type))
+ Fn->addFnAttr(llvm::Attribute::SanitizeType);
if (SanOpts.hasOneOf(SanitizerKind::Memory | SanitizerKind::KernelMemory))
Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
}
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index d78f2594a23764..891af7252b24a6 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -391,8 +391,8 @@ CodeGenModule::CodeGenModule(ASTContext &C,
if (LangOpts.HLSL)
createHLSLRuntime();
- // Enable TBAA unless it's suppressed. ThreadSanitizer needs TBAA even at O0.
- if (LangOpts.Sanitize.has(SanitizerKind::Thread) ||
+ // Enable TBAA unless it's suppressed. TSan and TySan need TBAA even at O0.
+ if (LangOpts.Sanitize.hasOneOf(SanitizerKind::Thread | SanitizerKind::Type) ||
(!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0))
TBAA.reset(new CodeGenTBAA(Context, TheModule, CodeGenOpts, getLangOpts(),
getCXXABI().getMangleContext()));
@@ -4924,7 +4924,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty,
}
if (D)
- SanitizerMD->reportGlobal(GV, *D);
+ SanitizerMD->reportGlobalToASan(GV, *D);
LangAS ExpectedAS =
D ? D->getType().getAddressSpace()
@@ -5465,7 +5465,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
if (NeedsGlobalCtor || NeedsGlobalDtor)
EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor);
- SanitizerMD->reportGlobal(GV, *D, NeedsGlobalCtor);
+ SanitizerMD->reportGlobalToASan(GV, *D, NeedsGlobalCtor);
+ SanitizerMD->reportGlobalToTySan(GV, *D);
// Emit global variable debug information.
if (CGDebugInfo *DI = getModuleDebugInfo())
@@ -6341,7 +6342,8 @@ CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S,
if (Entry)
*Entry = GV;
- SanitizerMD->reportGlobal(GV, S->getStrTokenLoc(0), "<string literal>");
+ SanitizerMD->reportGlobalToASan(GV, S->getStrTokenLoc(0), "<string literal>");
+ // FIXME: Should we also report to the TySan?
return ConstantAddress(castStringLiteralToDefaultAddressSpace(*this, GV),
GV->getValueType(), Alignment);
diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp
index dc288bc3f6157a..861b2b35a27d13 100644
--- a/clang/lib/CodeGen/CodeGenTBAA.cpp
+++ b/clang/lib/CodeGen/CodeGenTBAA.cpp
@@ -226,8 +226,10 @@ llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) {
}
llvm::MDNode *CodeGenTBAA::getTypeInfo(QualType QTy) {
- // At -O0 or relaxed aliasing, TBAA is not emitted for regular types.
- if (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing)
+ // At -O0 or relaxed aliasing, TBAA is not emitted for regular types (unless
+ // we're running TypeSanitizer).
+ if (!Features.Sanitize.has(SanitizerKind::Type) &&
+ (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing))
return nullptr;
// If the type has the may_alias attribute (even on a typedef), it is
diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp
index 53161c316c58a4..c0d38d3c747dea 100644
--- a/clang/lib/CodeGen/SanitizerMetadata.cpp
+++ b/clang/lib/CodeGen/SanitizerMetadata.cpp
@@ -34,11 +34,11 @@ SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) {
return Mask;
}
-void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
- SourceLocation Loc, StringRef Name,
- QualType Ty,
- SanitizerMask NoSanitizeAttrMask,
- bool IsDynInit) {
+void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
+ SourceLocation Loc, StringRef Name,
+ QualType Ty,
+ SanitizerMask NoSanitizeAttrMask,
+ bool IsDynInit) {
SanitizerSet FsanitizeArgument = CGM.getLangOpts().Sanitize;
if (!isAsanHwasanOrMemTag(FsanitizeArgument))
return;
@@ -75,8 +75,8 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
GV->setSanitizerMetadata(Meta);
}
-void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
- bool IsDynInit) {
+void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
+ const VarDecl &D, bool IsDynInit) {
if (!isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize))
return;
std::string QualName;
@@ -94,10 +94,34 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
return NoSanitizeMask;
};
- reportGlobal(GV, D.getLocation(), OS.str(), D.getType(), getNoSanitizeMask(D),
- IsDynInit);
+ reportGlobalToASan(GV, D.getLocation(), OS.str(), D.getType(),
+ getNoSanitizeMask(D), IsDynInit);
+}
+
+void SanitizerMetadata::reportGlobalToTySan(llvm::GlobalVariable *GV,
+ const VarDecl &D) {
+ if (!CGM.getLangOpts().Sanitize.has(SanitizerKind::Type))
+ return;
+
+ for (auto Attr : D.specific_attrs<NoSanitizeAttr>())
+ if (Attr->getMask() & SanitizerKind::Type)
+ return;
+
+ QualType QTy = D.getType();
+ llvm::MDNode *TBAAInfo = CGM.getTBAATypeInfo(QTy);
+ if (!TBAAInfo || TBAAInfo == CGM.getTBAATypeInfo(CGM.getContext().CharTy))
+ return;
+
+ llvm::Metadata *GlobalMetadata[] = {llvm::ConstantAsMetadata::get(GV),
+ TBAAInfo};
+
+ llvm::MDNode *ThisGlobal =
+ llvm::MDNode::get(CGM.getLLVMContext(), GlobalMetadata);
+ llvm::NamedMDNode *TysanGlobals =
+ CGM.getModule().getOrInsertNamedMetadata("llvm.tysan.globals");
+ TysanGlobals->addOperand(ThisGlobal);
}
void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {
- reportGlobal(GV, SourceLocation(), "", QualType(), SanitizerKind::All);
+ reportGlobalToASan(GV, SourceLocation(), "", QualType(), SanitizerKind::All);
}
diff --git a/clang/lib/CodeGen/SanitizerMetadata.h b/clang/lib/CodeGen/SanitizerMetadata.h
index 000f02cf8dcf11..9de087c518c6ad 100644
--- a/clang/lib/CodeGen/SanitizerMetadata.h
+++ b/clang/lib/CodeGen/SanitizerMetadata.h
@@ -37,12 +37,13 @@ class SanitizerMetadata {
public:
SanitizerMetadata(CodeGenModule &CGM);
- void reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
- bool IsDynInit = false);
- void reportGlobal(llvm::GlobalVariable *GV, SourceLocation Loc,
- StringRef Name, QualType Ty = {},
- SanitizerMask NoSanitizeAttrMask = {},
- bool IsDynInit = false);
+ void reportGlobalToASan(llvm::GlobalVariable *GV, const VarDecl &D,
+ bool IsDynInit = false);
+ void reportGlobalToASan(llvm::GlobalVariable *GV, SourceLocation Loc,
+ StringRef Name, QualType Ty = {},
+ SanitizerMask NoSanitizeAttrMask = {},
+ bool IsDynInit = false);
+ void reportGlobalToTySan(llvm::GlobalVariable *GV, const VarDecl &D);
void disableSanitizerForGlobal(llvm::GlobalVariable *GV);
};
} // end namespace CodeGen
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index ad68c086b71790..6865451b8bb7e4 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -42,14 +42,14 @@ static const SanitizerMask NotAllowedWithExecuteOnly =
static const SanitizerMask RequiresPIE =
SanitizerKind::DataFlow | SanitizerKind::Scudo;
static const SanitizerMask NeedsUnwindTables =
- SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread |
- SanitizerKind::Memory | SanitizerKind::DataFlow;
+ SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Type |
+ SanitizerKind::Thread | SanitizerKind::Memory | SanitizerKind::DataFlow;
static const SanitizerMask SupportsCoverage =
SanitizerKind::Address | SanitizerKind::HWAddress |
SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress |
- SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap |
- SanitizerKind::MemtagGlobals | SanitizerKind::Memory |
- SanitizerKind::KernelMemory | SanitizerKind::Leak |
+ SanitizerKind::Type | SanitizerKind::MemtagStack |
+ SanitizerKind::MemtagHeap | SanitizerKind::MemtagGlobals |
+ SanitizerKind::Memory | SanitizerKind::KernelMemory | SanitizerKind::Leak |
SanitizerKind::Undefined | SanitizerKind::Integer | SanitizerKind::Bounds |
SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
SanitizerKind::DataFlow | SanitizerKind::Fuzzer |
@@ -178,6 +178,7 @@ static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds,
{"memtag_ignorelist.txt", SanitizerKind::MemTag},
{"msan_ignorelist.txt", SanitizerKind::Memory},
{"tsan_ignorelist.txt", SanitizerKind::Thread},
+ {"tysan_blacklist.txt", SanitizerKind::Type},
{"dfsan_abilist.txt", SanitizerKind::DataFlow},
{"cfi_ignorelist.txt", SanitizerKind::CFI},
{"ubsan_ignorelist.txt",
@@ -516,6 +517,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = {
std::make_pair(SanitizerKind::Address,
SanitizerKind::Thread | SanitizerKind::Memory),
+ std::make_pair(SanitizerKind::Type,
+ SanitizerKind::Address | SanitizerKind::KernelAddress |
+ SanitizerKind::Memory | SanitizerKind::Leak |
+ SanitizerKind::Thread | SanitizerKind::KernelAddress),
std::make_pair(SanitizerKind::Thread, SanitizerKind::Memory),
std::make_pair(SanitizerKind::Leak,
SanitizerKind::Thread | SanitizerKind::Memory),
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 6eb0ed8f3fed9a..bb2b85c0553d72 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -1337,8 +1337,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
if (SanArgs.needsScudoRt()) {
SharedRuntimes.push_back("scudo_standalone");
}
- if (SanArgs.needsTsanRt())
+ if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes())
SharedRuntimes.push_back("tsan");
+ if (SanArgs.needsTysanRt())
+ StaticRuntimes.push_back("tysan");
if (SanArgs.needsHwasanRt()) {
if (SanArgs.needsHwasanAliasesRt())
SharedRuntimes.push_back("hwasan_aliases");
@@ -1403,6 +1405,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("tsan_cxx");
}
+ if (!SanArgs.needsSharedRt() && SanArgs.needsTysanRt())
+ StaticRuntimes.push_back("tysan");
if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt()) {
if (SanArgs.requiresMinimalRuntime()) {
StaticRuntimes.push_back("ubsan_minimal");
diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp
index 65846cace461e3..02028bc1a50cc7 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -1505,6 +1505,8 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
"Static sanitizer runtimes not supported");
AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan");
}
+ if (Sanitize.needsTysanRt())
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "tysan");
if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) {
AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false);
@@ -3373,6 +3375,9 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
isTargetTvOSSimulator() || isTargetWatchOSSimulator())) {
Res |= SanitizerKind::Thread;
}
+ if ((IsX86_64 || IsAArch64) && isTargetMacOSBased()) {
+ Res |= SanitizerKind::Type;
+ }
return Res;
}
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index 735af54f114cef..97a8d2a29f1b95 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -803,6 +803,8 @@ SanitizerMask Linux::getSupportedSanitizers() const {
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ ||
IsLoongArch64 || IsRISCV64)
Res |= SanitizerKind::Thread;
+ if (IsX86_64 || IsAArch64)
+ Res |= SanitizerKind::Type;
if (IsX86_64 || IsSystemZ)
Res |= SanitizerKind::KernelMemory;
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch ||
diff --git a/clang/test/CodeGen/sanitize-type-attr.cpp b/clang/test/CodeGen/sanitize-type-attr.cpp
new file mode 100644
index 00000000000000..4da8488e1f9486
--- /dev/null
+++ b/clang/test/CodeGen/sanitize-type-attr.cpp
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -fsanitize=type | FileCheck -check-prefix=TYSAN %s
+// RUN: echo "src:%s" | sed -e 's/\\/\\\\/g' > %t
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -fsanitize=type -fsanitize-blacklist=%t | FileCheck -check-prefix=BL %s
+
+// The sanitize_type attribute should be attached to functions
+// when TypeSanitizer is enabled, unless no_sanitize("type") attribute
+// is present.
+
+// WITHOUT: NoTYSAN1{{.*}}) [[NOATTR:#[0-9]+]]
+// BL: NoTYSAN1{{.*}}) [[NOATTR:#[0-9]+]]
+// TYSAN: NoTYSAN1{{.*}}) [[NOATTR:#[0-9]+]]
+__attribute__((no_sanitize("type"))) int NoTYSAN1(int *a) { return *a; }
+
+// WITHOUT: NoTYSAN2{{.*}}) [[NOATTR]]
+// BL: NoTYSAN2{{.*}}) [[NOATTR]]
+// TYSAN: NoTYSAN2{{.*}}) [[NOATTR]]
+__attribute__((no_sanitize("type"))) int NoTYSAN2(int *a);
+int NoTYSAN2(int *a) { return *a; }
+
+// WITHOUT: NoTYSAN3{{.*}}) [[NOATTR:#[0-9]+]]
+// BL: NoTYSAN3{{.*}}) [[NOATTR:#[0-9]+]]
+// TYSAN: NoTYSAN3{{.*}}) [[NOATTR:#[0-9]+]]
+__attribute__((no_sanitize("type"))) int NoTYSAN3(int *a) { return *a; }
+
+// WITHOUT: TYSANOk{{.*}}) [[NOATTR]]
+// BL: TYSANOk{{.*}}) [[NOATTR]]
+// TYSAN: TYSANOk{{.*}}) [[WITH:#[0-9]+]]
+int TYSANOk(int *a) { return *a; }
+
+// WITHOUT: TemplateTYSANOk{{.*}}) [[NOATTR]]
+// BL: TemplateTYSANOk{{.*}}) [[NOATTR]]
+// TYSAN: TemplateTYSANOk{{.*}}) [[WITH]]
+template <int i>
+int TemplateTYSANOk() { return i; }
+
+// WITHOUT: TemplateNoTYSAN{{.*}}) [[NOATTR]]
+// BL: TemplateNoTYSAN{{.*}}) [[NOATTR]]
+// TYSAN: TemplateNoTYSAN{{.*}}) [[NOATTR]]
+template <int i>
+__attribute__((no_sanitize("type"))) int TemplateNoTYSAN() { return i; }
+
+int force_instance = TemplateTYSANOk<42>() + TemplateNoTYSAN<42>();
+
+// Check that __cxx_global_var_init* get the sanitize_type attribute.
+int global1 = 0;
+int global2 = *(int *)((char *)&global1 + 1);
+// WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR:#[0-9]+]]
+// BL: @__cxx_global_var_init{{.*}}[[NOATTR:#[0-9]+]]
+// TYSAN: @__cxx_global_var_init{{.*}}[[WITH:#[0-9]+]]
+
+// Make sure that we don't add globals to the list for which we don't have a
+// specific type description.
+// FIXME: We now have a type description for this type and a global is added. Should it?
+struct SX {
+ int a, b;
+};
+SX sx;
+
+// WITHOUT: attributes [[NOATTR]] = { noinline nounwind{{.*}} }
+
+// BL: attributes [[NOATTR]] = { noinline nounwind{{.*}} }
+
+// TYSAN: attributes [[NOATTR]] = { mustprogress noinline nounwind{{.*}} }
+// TYSAN: attributes [[WITH]] = { noinline nounwind sanitize_type{{.*}} }
+
+// TYSAN-DAG: !llvm.tysan.globals = !{[[G1MD:![0-9]+]], [[G2MD:![0-9]+]], [[G3MD:![0-9]+]], [[SXMD:![0-9]+]]}
+// TYSAN-DAG: [[G1MD]] = !{ptr @force_instance, [[INTMD:![0-9]+]]}
+// TYSAN-DAG: [[INTMD]] = !{!"int",
+// TYSAN-DAG: [[G2MD]] = !{ptr @global1, [[INTMD]]}
+// TYSAN-DAG: [[G3MD]] = !{ptr @global2, [[INTMD]]}
+// TYSAN-DAG: [[SXMD]] = !{ptr @sx, [[SXTYMD:![0-9]+]]}
+// TYSAN-DAG: [[SXTYMD]] = !{!"_ZTS2SX", [[INTMD]], i64 0, !1, i64 4}
+// TYSAN-DAG: Simple C++ TBAA
diff --git a/clang/test/Driver/sanitizer-ld.c b/clang/test/Driver/sanitizer-ld.c
index 2831c2dad8d24c..73e243cb159ef0 100644
--- a/clang/test/Driver/sanitizer-ld.c
+++ b/clang/test/Driver/sanitizer-ld.c
@@ -261,6 +261,29 @@
// CHECK-ASAN-ANDROID-SHARED-NOT: "-lpthread"
// CHECK-ASAN-ANDROID-SHARED-NOT: "-lresolv"
+
+// RUN: %clangxx %s -### -o %t.o 2>&1 \
+// RUN: --target=x86_64-unknown-linux -fuse-ld=ld -stdlib=platform -lstdc++ \
+// RUN: -fsanitize=type \
+// RUN: -resource-dir=%S/Inputs/resource_dir \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-TYSAN-LINUX-CXX %s
+//
+// CHECK-TYSAN-LINUX-CXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-TYSAN-LINUX-CXX-NOT: stdc++
+// CHECK-TYSAN-LINUX-CXX: "--whole-archive" "{{.*}}libclang_rt.tysan{{[^.]*}}.a" "--no-whole-archive"
+// CHECK-TYSAN-LINUX-CXX: stdc++
+
+// RUN: %clangxx -fsanitize=type -### %s 2>&1 \
+// RUN: -mmacosx-version-min=10.6 \
+// RUN: --target=x86_64-apple-darwin13.4.0 -fuse-ld=ld -stdlib=platform \
+// RUN: -resource-dir=%S/Inputs/resource_dir \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-TYSAN-DARWIN-CXX %s
+// CHECK-TYSAN-DARWIN-CXX: "{{.*}}ld{{(.exe)?}}"
+// CHECK-TYSAN-DARWIN-CXX: libclang_rt.tysan_osx_dynamic.dylib
+// CHECK-TYSAN-DARWIN-CXX-NOT: -lc++abi
+
// RUN: %clangxx -### %s 2>&1 \
// RUN: --target=x86_64-unknown-linux -fuse-ld=ld -stdlib=platform -lstdc++ \
// RUN: -fsanitize=thread \
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index c6f0ddf29a6da8..8d3259336abba9 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -724,6 +724,7 @@ enum AttributeKindCodes {
ATTR_KIND_WRITABLE = 89,
ATTR_KIND_CORO_ONLY_DESTROY_WHEN_COMPLETE = 90,
ATTR_KIND_DEAD_ON_UNWIND = 91,
+ ATTR_KIND_SANITIZE_TYPE = 92,
};
enum ComdatSelectionKindCodes {
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index 864f87f3383891..beffa63bd81298 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -270,6 +270,9 @@ def SanitizeAddress : EnumAttr<"sanitize_address", [FnAttr]>;
/// ThreadSanitizer is on.
def SanitizeThread : EnumAttr<"sanitize_thread", [FnAttr]>;
+/// TypeSanitizer is on.
+def SanitizeType : EnumAttr<"sanitize_type", [FnAttr]>;
+
/// MemorySanitizer is on.
def SanitizeMemory : EnumAttr<"sanitize_memory", [FnAttr]>;
@@ -354,6 +357,7 @@ def : CompatRule<"isEqual<SanitizeThreadAttr>">;
def : CompatRule<"isEqual<SanitizeMemoryAttr>">;
def : CompatRule<"isEqual<SanitizeHWAddressAttr>">;
def : CompatRule<"isEqual<SanitizeMemTagAttr>">;
+def : CompatRule<"isEqual<SanitizeTypeAttr>">;
def : CompatRule<"isEqual<SafeStackAttr>">;
def : CompatRule<"isEqual<ShadowCallStackAttr>">;
def : CompatRule<"isEqual<UseSampleProfileAttr>">;
diff --git a/llvm/include/llvm/Transforms/Instrumentation/TypeSanitizer.h b/llvm/include/llvm/Transforms/Instrumentation/TypeSanitizer.h
new file mode 100644
index 00000000000000..a6cc56df35f14d
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Instrumentation/TypeSanitizer.h
@@ -0,0 +1,38 @@
+//===- Transforms/Instrumentation/TypeSanitizer.h - TySan Pass -----------===//
+//
+// 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 defines the type sanitizer pass.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_TYPESANITIZER_H
+#define LLVM_TRANSFORMS_INSTRUMENTATION_TYPESANITIZER_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+class Function;
+class FunctionPass;
+class Module;
+
+/// A function pass for tysan instrumentation.
+struct TypeSanitizerPass : public PassInfoMixin<TypeSanitizerPass> {
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
+ static bool isRequired() { return true; }
+};
+
+/// A module pass for tysan instrumentation.
+///
+/// Create ctor and init functions.
+struct ModuleTypeSanitizerPass : public PassInfoMixin<ModuleTypeSanitizerPass> {
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
+ static bool isRequired() { return true; }
+};
+
+} // namespace llvm
+#endif /* LLVM_TRANSFORMS_INSTRUMENTATION_TYPESANITIZER_H */
diff --git a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
index e4dc1a867f6f0c..bfa8a80518ccda 100644
--- a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
@@ -371,11 +371,27 @@ static bool isStructPathTBAA(const MDNode *MD) {
return isa<MDNode>(MD->getOperand(0)) && MD->getNumOperands() >= 3;
}
+// When using the TypeSanitizer, don't use TBAA information for alias analysis.
+// This might cause us to remove memory accesses that we need to verify at
+// runtime.
+static bool usingSanitizeType(const Value *V) {
+ const Function *F;
+
+ if (auto *I = dyn_cast<Instruction>(V))
+ F = I->getParent()->getParent();
+ else if (auto *A = dyn_cast<Argument>(V))
+ F = A->getParent();
+ else
+ return false;
+
+ return F->hasFnAttribute(Attribute::SanitizeType);
+}
+
AliasResult TypeBasedAAResult::alias(const MemoryLocation &LocA,
const MemoryLocation &LocB,
AAQueryInfo &AAQI, const Instruction *) {
- if (!EnableTBAA)
- return AliasResult::MayAlias;
+ if (!EnableTBAA || usingSanitizeType(LocA.Ptr) || usingSanitizeType(LocB.Ptr))
+ return AAResultBase::alias(LocA, LocB, AAQI, nullptr);
if (Aliases(LocA.AATags.TBAA, LocB.AATags.TBAA))
return AliasResult::MayAlias;
@@ -425,8 +441,8 @@ MemoryEffects TypeBasedAAResult::getMemoryEffects(const Function *F) {
ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call,
const MemoryLocation &Loc,
AAQueryInfo &AAQI) {
- if (!EnableTBAA)
- return ModRefInfo::ModRef;
+ if (!EnableTBAA || usingSanitizeType(Call))
+ return AAResultBase::getModRefInfo(Call, Loc, AAQI);
if (const MDNode *L = Loc.AATags.TBAA)
if (const MDNode *M = Call->getMetadata(LLVMContext::MD_tbaa))
@@ -439,8 +455,8 @@ ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call,
ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call1,
const CallBase *Call2,
AAQueryInfo &AAQI) {
- if (!EnableTBAA)
- return ModRefInfo::ModRef;
+ if (!EnableTBAA || usingSanitizeType(Call1))
+ return AAResultBase::getModRefInfo(Call1, Call2, AAQI);
if (const MDNode *M1 = Call1->getMetadata(LLVMContext::MD_tbaa))
if (const MDNode *M2 = Call2->getMetadata(LLVMContext::MD_tbaa))
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 8907f6fa4ff3fd..31e2d74fe570e8 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2058,6 +2058,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::SanitizeHWAddress;
case bitc::ATTR_KIND_SANITIZE_THREAD:
return Attribute::SanitizeThread;
+ case bitc::ATTR_KIND_SANITIZE_TYPE:
+ return Attribute::SanitizeType;
case bitc::ATTR_KIND_SANITIZE_MEMORY:
return Attribute::SanitizeMemory;
case bitc::ATTR_KIND_SPECULATIVE_LOAD_HARDENING:
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 8fca569a391baf..c925c367d17aaf 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -789,6 +789,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_SANITIZE_HWADDRESS;
case Attribute::SanitizeThread:
return bitc::ATTR_KIND_SANITIZE_THREAD;
+ case Attribute::SanitizeType:
+ return bitc::ATTR_KIND_SANITIZE_TYPE;
case Attribute::SanitizeMemory:
return bitc::ATTR_KIND_SANITIZE_MEMORY;
case Attribute::SpeculativeLoadHardening:
diff --git a/llvm/lib/CodeGen/ShrinkWrap.cpp b/llvm/lib/CodeGen/ShrinkWrap.cpp
index ab57d08e527e4d..f4e6f8001debf2 100644
--- a/llvm/lib/CodeGen/ShrinkWrap.cpp
+++ b/llvm/lib/CodeGen/ShrinkWrap.cpp
@@ -984,6 +984,7 @@ bool ShrinkWrap::isShrinkWrapEnabled(const MachineFunction &MF) {
!(MF.getFunction().hasFnAttribute(Attribute::SanitizeAddress) ||
MF.getFunction().hasFnAttribute(Attribute::SanitizeThread) ||
MF.getFunction().hasFnAttribute(Attribute::SanitizeMemory) ||
+ MF.getFunction().hasFnAttribute(Attribute::SanitizeType) ||
MF.getFunction().hasFnAttribute(Attribute::SanitizeHWAddress));
// If EnableShrinkWrap is set, it takes precedence on whatever the
// target sets. The rational is that we assume we want to test
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index f94bd422c6b592..fb56a65e41ec99 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -167,6 +167,7 @@
#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
+#include "llvm/Transforms/Instrumentation/TypeSanitizer.h"
#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Scalar/ADCE.h"
#include "llvm/Transforms/Scalar/AlignmentFromAssumptions.h"
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 82ce040c649626..5c9e16435f0ae9 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -138,6 +138,7 @@ MODULE_PASS("synthetic-counts-propagation", SyntheticCountsPropagation())
MODULE_PASS("trigger-crash", TriggerCrashPass())
MODULE_PASS("trigger-verifier-error", TriggerVerifierErrorPass())
MODULE_PASS("tsan-module", ModuleThreadSanitizerPass())
+MODULE_PASS("tysan-module", ModuleTypeSanitizerPass())
MODULE_PASS("verify", VerifierPass())
MODULE_PASS("view-callgraph", CallGraphViewerPass())
MODULE_PASS("wholeprogramdevirt", WholeProgramDevirtPass())
@@ -417,6 +418,7 @@ FUNCTION_PASS("tlshoist", TLSVariableHoistPass())
FUNCTION_PASS("transform-warning", WarnMissedTransformationsPass())
FUNCTION_PASS("trigger-verifier-error", TriggerVerifierErrorPass())
FUNCTION_PASS("tsan", ThreadSanitizerPass())
+FUNCTION_PASS("tysan", TypeSanitizerPass())
FUNCTION_PASS("typepromotion", TypePromotionPass(TM))
FUNCTION_PASS("unify-loop-exits", UnifyLoopExitsPass())
FUNCTION_PASS("vector-combine", VectorCombinePass())
diff --git a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
index 424f1d43360677..54211236e18643 100644
--- a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
+++ b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
@@ -20,6 +20,7 @@ add_llvm_component_library(LLVMInstrumentation
SanitizerBinaryMetadata.cpp
ValueProfileCollector.cpp
ThreadSanitizer.cpp
+ TypeSanitizer.cpp
HWAddressSanitizer.cpp
ADDITIONAL_HEADER_DIRS
diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
new file mode 100644
index 00000000000000..ed4aba4ad612d9
--- /dev/null
+++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
@@ -0,0 +1,873 @@
+//===----- TypeSanitizer.cpp - type-based-aliasing-violation detector -----===//
+//
+// 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, a type-based-aliasing-violation
+// detector.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Instrumentation/TypeSanitizer.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Analysis/MemoryLocation.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/MDBuilder.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
+#include "llvm/ProfileData/InstrProf.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MD5.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/Instrumentation.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Local.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
+
+#include <cctype>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "tysan"
+
+static const char *const kTysanModuleCtorName = "tysan.module_ctor";
+static const char *const kTysanInitName = "__tysan_init";
+static const char *const kTysanCheckName = "__tysan_check";
+static const char *const kTysanGVNamePrefix = "__tysan_v1_";
+
+static const char *const kTysanShadowMemoryAddress =
+ "__tysan_shadow_memory_address";
+static const char *const kTysanAppMemMask = "__tysan_app_memory_mask";
+
+static cl::opt<bool>
+ ClWritesAlwaysSetType("tysan-writes-always-set-type",
+ cl::desc("Writes always set the type"), cl::Hidden,
+ cl::init(false));
+
+STATISTIC(NumInstrumentedAccesses, "Number of instrumented accesses");
+
+static Regex AnonNameRegex("^_ZTS.*N[1-9][0-9]*_GLOBAL__N");
+
+namespace {
+
+/// TypeSanitizer: instrument the code in module to find type-based aliasing
+/// violations.
+struct TypeSanitizer {
+ TypeSanitizer(Module &M);
+ bool run(Function &F, const TargetLibraryInfo &TLI);
+ void instrumentGlobals();
+
+private:
+ typedef SmallDenseMap<const MDNode *, GlobalVariable *, 8>
+ TypeDescriptorsMapTy;
+ typedef SmallDenseMap<const MDNode *, std::string, 8> TypeNameMapTy;
+
+ void initializeCallbacks(Module &M);
+
+ Value *getShadowBase(Function &F);
+ Value *getAppMemMask(Function &F);
+
+ bool instrumentWithShadowUpdate(IRBuilder<> &IRB, const MDNode *TBAAMD,
+ Value *Ptr, uint64_t AccessSize, bool IsRead,
+ bool IsWrite, Value *&ShadowBase,
+ Value *&AppMemMask, bool ForceSetType,
+ bool SanitizeFunction,
+ TypeDescriptorsMapTy &TypeDescriptors,
+ const DataLayout &DL);
+ bool instrumentMemoryAccess(Instruction *I, MemoryLocation &MLoc,
+ Value *&ShadowBase, Value *&AppMemMask,
+ bool SanitizeFunction,
+ TypeDescriptorsMapTy &TypeDescriptors,
+ const DataLayout &DL);
+ bool instrumentMemInst(Value *I, Value *&ShadowBase, Value *&AppMemMask,
+ const DataLayout &DL);
+
+ std::string getAnonymousStructIdentifier(const MDNode *MD,
+ TypeNameMapTy &TypeNames);
+ bool generateTypeDescriptor(const MDNode *MD,
+ TypeDescriptorsMapTy &TypeDescriptors,
+ TypeNameMapTy &TypeNames, Module &M);
+ bool generateBaseTypeDescriptor(const MDNode *MD,
+ TypeDescriptorsMapTy &TypeDescriptors,
+ TypeNameMapTy &TypeNames, Module &M);
+
+ const Triple TargetTriple;
+ Type *IntptrTy;
+ uint64_t PtrShift;
+ IntegerType *OrdTy;
+
+ // Callbacks to run-time library are computed in doInitialization.
+ Function *TysanCheck;
+ Function *TysanCtorFunction;
+ Function *TysanGlobalsSetTypeFunction;
+};
+} // namespace
+
+TypeSanitizer::TypeSanitizer(Module &M)
+ : TargetTriple(Triple(M.getTargetTriple())) {
+ const DataLayout &DL = M.getDataLayout();
+ IntptrTy = DL.getIntPtrType(M.getContext());
+ PtrShift = countr_zero(IntptrTy->getPrimitiveSizeInBits() / 8);
+
+ TysanGlobalsSetTypeFunction = M.getFunction("__tysan_set_globals_types");
+ initializeCallbacks(M);
+}
+
+void TypeSanitizer::initializeCallbacks(Module &M) {
+ IRBuilder<> IRB(M.getContext());
+ OrdTy = IRB.getInt32Ty();
+
+ AttributeList Attr;
+ Attr = Attr.addFnAttribute(M.getContext(), Attribute::NoUnwind);
+ // Initialize the callbacks.
+ TysanCheck = cast<Function>(
+ M.getOrInsertFunction(kTysanCheckName, Attr, IRB.getVoidTy(),
+ IRB.getPtrTy(), // Pointer to data to be read.
+ OrdTy, // Size of the data in bytes.
+ IRB.getPtrTy(), // Pointer to type descriptor.
+ OrdTy // Flags.
+ )
+ .getCallee());
+
+ TysanCtorFunction = cast<Function>(
+ M.getOrInsertFunction(kTysanModuleCtorName, Attr, IRB.getVoidTy())
+ .getCallee());
+}
+
+void TypeSanitizer::instrumentGlobals() {
+ Module &M = *TysanCtorFunction->getParent();
+ initializeCallbacks(M);
+ TysanGlobalsSetTypeFunction = nullptr;
+
+ NamedMDNode *Globals = M.getNamedMetadata("llvm.tysan.globals");
+ if (!Globals)
+ return;
+
+ const DataLayout &DL = M.getDataLayout();
+ Value *ShadowBase = nullptr, *AppMemMask = nullptr;
+ TypeDescriptorsMapTy TypeDescriptors;
+ TypeNameMapTy TypeNames;
+
+ for (const auto &GMD : Globals->operands()) {
+ auto *GV = mdconst::dyn_extract_or_null<GlobalVariable>(GMD->getOperand(0));
+ if (!GV)
+ continue;
+ const MDNode *TBAAMD = cast<MDNode>(GMD->getOperand(1));
+ if (!generateBaseTypeDescriptor(TBAAMD, TypeDescriptors, TypeNames, M))
+ continue;
+
+ if (!TysanGlobalsSetTypeFunction) {
+ TysanGlobalsSetTypeFunction = Function::Create(
+ FunctionType::get(Type::getVoidTy(M.getContext()), false),
+ GlobalValue::InternalLinkage, "__tysan_set_globals_types", &M);
+ BasicBlock *BB =
+ BasicBlock::Create(M.getContext(), "", TysanGlobalsSetTypeFunction);
+ ReturnInst::Create(M.getContext(), BB);
+ }
+
+ IRBuilder<> IRB(
+ TysanGlobalsSetTypeFunction->getEntryBlock().getTerminator());
+ Type *AccessTy = GV->getValueType();
+ assert(AccessTy->isSized());
+ uint64_t AccessSize = DL.getTypeStoreSize(AccessTy);
+ instrumentWithShadowUpdate(IRB, TBAAMD, GV, AccessSize, false, false,
+ ShadowBase, AppMemMask, true, false,
+ TypeDescriptors, DL);
+ }
+
+ if (TysanGlobalsSetTypeFunction) {
+ IRBuilder<> IRB(TysanCtorFunction->getEntryBlock().getTerminator());
+ IRB.CreateCall(TysanGlobalsSetTypeFunction, {});
+ }
+}
+
+static void insertModuleCtor(Module &M) {
+ Function *TysanCtorFunction;
+ std::tie(TysanCtorFunction, std::ignore) =
+ createSanitizerCtorAndInitFunctions(M, kTysanModuleCtorName,
+ kTysanInitName, /*InitArgTypes=*/{},
+ /*InitArgs=*/{});
+
+ TypeSanitizer TySan(M);
+ TySan.instrumentGlobals();
+ appendToGlobalCtors(M, TysanCtorFunction, 0);
+}
+
+static const char LUT[] = "0123456789abcdef";
+
+static std::string encodeName(StringRef Name) {
+ size_t Length = Name.size();
+ std::string Output = kTysanGVNamePrefix;
+ Output.reserve(Output.size() + 3 * Length);
+ for (size_t i = 0; i < Length; ++i) {
+ const unsigned char c = Name[i];
+ if (isalnum((int)c)) {
+ Output.push_back(c);
+ continue;
+ }
+
+ if (c == '_') {
+ Output.append("__");
+ continue;
+ }
+
+ Output.push_back('_');
+ Output.push_back(LUT[c >> 4]);
+ Output.push_back(LUT[c & 15]);
+ }
+
+ return Output;
+}
+
+static bool isAnonymousNamespaceName(StringRef Name) {
+ // Types that are in an anonymous namespace are local to this module.
+ // FIXME: This should really be marked by the frontend in the metadata
+ // instead of having us guess this from the mangled name. Moreover, the regex
+ // here can pick up (unlikely) names in the non-reserved namespace (because
+ // it needs to search into the type to pick up cases where the type in the
+ // anonymous namespace is a template parameter, etc.).
+ return AnonNameRegex.match(Name);
+}
+
+std::string
+TypeSanitizer::getAnonymousStructIdentifier(const MDNode *MD,
+ TypeNameMapTy &TypeNames) {
+ MD5 Hash;
+
+ for (int i = 1, e = MD->getNumOperands(); i < e; i += 2) {
+ const MDNode *MemberNode = dyn_cast<MDNode>(MD->getOperand(i));
+ if (!MemberNode)
+ return "";
+
+ auto TNI = TypeNames.find(MemberNode);
+ std::string MemberName;
+ if (TNI != TypeNames.end()) {
+ MemberName = TNI->second;
+ } else {
+ if (MemberNode->getNumOperands() < 1)
+ return "";
+ MDString *MemberNameNode = dyn_cast<MDString>(MemberNode->getOperand(0));
+ if (!MemberNameNode)
+ return "";
+ MemberName = MemberNameNode->getString().str();
+ if (MemberName.empty())
+ MemberName = getAnonymousStructIdentifier(MemberNode, TypeNames);
+ if (MemberName.empty())
+ return "";
+ TypeNames[MemberNode] = MemberName;
+ }
+
+ Hash.update(MemberName);
+ Hash.update("\0");
+
+ uint64_t Offset =
+ mdconst::extract<ConstantInt>(MD->getOperand(i + 1))->getZExtValue();
+ Hash.update(utostr(Offset));
+ Hash.update("\0");
+ }
+
+ MD5::MD5Result HashResult;
+ Hash.final(HashResult);
+ return "__anonymous_" + std::string(HashResult.digest().str());
+}
+
+bool TypeSanitizer::generateBaseTypeDescriptor(
+ const MDNode *MD, TypeDescriptorsMapTy &TypeDescriptors,
+ TypeNameMapTy &TypeNames, Module &M) {
+ if (MD->getNumOperands() < 1)
+ return false;
+
+ MDString *NameNode = dyn_cast<MDString>(MD->getOperand(0));
+ if (!NameNode)
+ return false;
+
+ std::string Name = NameNode->getString().str();
+ if (Name.empty())
+ Name = getAnonymousStructIdentifier(MD, TypeNames);
+ if (Name.empty())
+ return false;
+ TypeNames[MD] = Name;
+ std::string EncodedName = encodeName(Name);
+
+ GlobalVariable *GV =
+ dyn_cast_or_null<GlobalVariable>(M.getNamedValue(EncodedName));
+ if (GV) {
+ TypeDescriptors[MD] = GV;
+ return true;
+ }
+
+ SmallVector<std::pair<Constant *, uint64_t>> Members;
+ for (int i = 1, e = MD->getNumOperands(); i < e; i += 2) {
+ const MDNode *MemberNode = dyn_cast<MDNode>(MD->getOperand(i));
+ if (!MemberNode)
+ return false;
+
+ Constant *Member;
+ auto TDI = TypeDescriptors.find(MemberNode);
+ if (TDI != TypeDescriptors.end()) {
+ Member = TDI->second;
+ } else {
+ if (!generateBaseTypeDescriptor(MemberNode, TypeDescriptors, TypeNames,
+ M))
+ return false;
+
+ Member = TypeDescriptors[MemberNode];
+ }
+
+ uint64_t Offset =
+ mdconst::extract<ConstantInt>(MD->getOperand(i + 1))->getZExtValue();
+
+ Members.push_back(std::make_pair(Member, Offset));
+ }
+
+ // The descriptor for a scalar is:
+ // [2, member count, [type pointer, offset]..., name]
+
+ LLVMContext &C = MD->getContext();
+ Constant *NameData = ConstantDataArray::getString(C, NameNode->getString());
+ SmallVector<Type *> TDSubTys;
+ SmallVector<Constant *> TDSubData;
+
+ TDSubTys.push_back(IntptrTy);
+ TDSubData.push_back(ConstantInt::get(IntptrTy, 2));
+
+ TDSubTys.push_back(IntptrTy);
+ TDSubData.push_back(ConstantInt::get(IntptrTy, Members.size()));
+
+ bool ShouldBeComdat = !isAnonymousNamespaceName(NameNode->getString());
+ for (auto &Member : Members) {
+ TDSubTys.push_back(Member.first->getType());
+ TDSubData.push_back(Member.first);
+
+ TDSubTys.push_back(IntptrTy);
+ TDSubData.push_back(ConstantInt::get(IntptrTy, Member.second));
+ }
+
+ TDSubTys.push_back(NameData->getType());
+ TDSubData.push_back(NameData);
+
+ StructType *TDTy = StructType::get(C, TDSubTys);
+ Constant *TD = ConstantStruct::get(TDTy, TDSubData);
+
+ GlobalVariable *TDGV =
+ new GlobalVariable(TDTy, true,
+ !ShouldBeComdat ? GlobalValue::InternalLinkage
+ : GlobalValue::LinkOnceODRLinkage,
+ TD, EncodedName);
+ M.insertGlobalVariable(TDGV);
+
+ if (ShouldBeComdat) {
+ if (TargetTriple.isOSBinFormatELF()) {
+ Comdat *TDComdat = M.getOrInsertComdat(EncodedName);
+ TDGV->setComdat(TDComdat);
+ }
+ appendToUsed(M, TDGV);
+ }
+
+ TypeDescriptors[MD] = TDGV;
+ return true;
+}
+
+bool TypeSanitizer::generateTypeDescriptor(
+ const MDNode *MD, TypeDescriptorsMapTy &TypeDescriptors,
+ TypeNameMapTy &TypeNames, Module &M) {
+ // Here we need to generate a type descriptor corresponding to this TBAA
+ // metadata node. Under the current scheme there are three kinds of TBAA
+ // metadata nodes: scalar nodes, struct nodes, and struct tag nodes.
+
+ if (MD->getNumOperands() < 3)
+ return false;
+
+ const MDNode *BaseNode = dyn_cast<MDNode>(MD->getOperand(0));
+ if (!BaseNode)
+ return false;
+
+ // This is a struct tag (element-access) node.
+
+ const MDNode *AccessNode = dyn_cast<MDNode>(MD->getOperand(1));
+ if (!AccessNode)
+ return false;
+
+ Constant *Base;
+ auto TDI = TypeDescriptors.find(BaseNode);
+ if (TDI != TypeDescriptors.end()) {
+ Base = TDI->second;
+ } else {
+ if (!generateBaseTypeDescriptor(BaseNode, TypeDescriptors, TypeNames, M))
+ return false;
+
+ Base = TypeDescriptors[BaseNode];
+ }
+
+ Constant *Access;
+ TDI = TypeDescriptors.find(AccessNode);
+ if (TDI != TypeDescriptors.end()) {
+ Access = TDI->second;
+ } else {
+ if (!generateBaseTypeDescriptor(AccessNode, TypeDescriptors, TypeNames, M))
+ return false;
+
+ Access = TypeDescriptors[AccessNode];
+ }
+
+ uint64_t Offset =
+ mdconst::extract<ConstantInt>(MD->getOperand(2))->getZExtValue();
+ std::string EncodedName =
+ std::string(Base->getName()) + "_o_" + utostr(Offset);
+
+ GlobalVariable *GV =
+ dyn_cast_or_null<GlobalVariable>(M.getNamedValue(EncodedName));
+ if (GV) {
+ TypeDescriptors[MD] = GV;
+ return true;
+ }
+
+ // The descriptor for a scalar is:
+ // [1, base-type pointer, access-type pointer, offset]
+
+ StructType *TDTy =
+ StructType::get(IntptrTy, Base->getType(), Access->getType(), IntptrTy);
+ Constant *TD =
+ ConstantStruct::get(TDTy, ConstantInt::get(IntptrTy, 1), Base, Access,
+ ConstantInt::get(IntptrTy, Offset));
+
+ bool ShouldBeComdat = cast<GlobalVariable>(Base)->getLinkage() ==
+ GlobalValue::LinkOnceODRLinkage;
+
+ GlobalVariable *TDGV =
+ new GlobalVariable(TDTy, true,
+ !ShouldBeComdat ? GlobalValue::InternalLinkage
+ : GlobalValue::LinkOnceODRLinkage,
+ TD, EncodedName);
+ M.insertGlobalVariable(TDGV);
+
+ if (ShouldBeComdat) {
+ if (TargetTriple.isOSBinFormatELF()) {
+ Comdat *TDComdat = M.getOrInsertComdat(EncodedName);
+ TDGV->setComdat(TDComdat);
+ }
+ appendToUsed(M, TDGV);
+ }
+
+ TypeDescriptors[MD] = TDGV;
+ return true;
+}
+
+Value *TypeSanitizer::getShadowBase(Function &F) {
+ IRBuilder<> IRB(&F.front().front());
+ Constant *GlobalShadowAddress =
+ F.getParent()->getOrInsertGlobal(kTysanShadowMemoryAddress, IntptrTy);
+ return IRB.CreateLoad(IntptrTy, GlobalShadowAddress, "shadow.base");
+}
+
+Value *TypeSanitizer::getAppMemMask(Function &F) {
+ IRBuilder<> IRB(&F.front().front());
+ Value *GlobalAppMemMask =
+ F.getParent()->getOrInsertGlobal(kTysanAppMemMask, IntptrTy);
+ return IRB.CreateLoad(IntptrTy, GlobalAppMemMask, "app.mem.mask");
+}
+
+bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) {
+ // This is required to prevent instrumenting call to __tysan_init from within
+ // the module constructor.
+ if (&F == TysanCtorFunction || &F == TysanGlobalsSetTypeFunction)
+ return false;
+ initializeCallbacks(*F.getParent());
+
+ SmallVector<std::pair<Instruction *, MemoryLocation>> MemoryAccesses;
+ SmallSetVector<const MDNode *, 8> TBAAMetadata;
+ SmallVector<Value *> MemTypeResetInsts;
+
+ bool Res = false;
+ bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeType);
+ const DataLayout &DL = F.getParent()->getDataLayout();
+ // Traverse all instructions, collect loads/stores/returns, check for calls.
+ for (auto &BB : F) {
+ for (auto &Inst : BB) {
+ // Skip memory accesses inserted by another instrumentation.
+ if (Inst.getMetadata(LLVMContext::MD_nosanitize))
+ continue;
+
+ if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst) ||
+ isa<AtomicCmpXchgInst>(Inst) || isa<AtomicRMWInst>(Inst)) {
+ MemoryLocation MLoc = MemoryLocation::get(&Inst);
+
+ // Swift errors are special (we can't introduce extra uses on them).
+ if (MLoc.Ptr->isSwiftError())
+ continue;
+
+ // Skip non-address-space-0 pointers; we don't know how to handle them.
+ Type *PtrTy = cast<PointerType>(MLoc.Ptr->getType());
+ if (PtrTy->getPointerAddressSpace() != 0)
+ continue;
+
+ if (MLoc.AATags.TBAA)
+ TBAAMetadata.insert(MLoc.AATags.TBAA);
+ MemoryAccesses.push_back(std::make_pair(&Inst, MLoc));
+ } else if (isa<CallInst>(Inst) || isa<InvokeInst>(Inst)) {
+ if (CallInst *CI = dyn_cast<CallInst>(&Inst))
+ maybeMarkSanitizerLibraryCallNoBuiltin(CI, &TLI);
+
+ if (isa<MemIntrinsic>(Inst)) {
+ MemTypeResetInsts.push_back(&Inst);
+ } else if (auto *II = dyn_cast<IntrinsicInst>(&Inst)) {
+ if (II->getIntrinsicID() == Intrinsic::lifetime_start ||
+ II->getIntrinsicID() == Intrinsic::lifetime_end)
+ MemTypeResetInsts.push_back(&Inst);
+ }
+ } else if (isa<AllocaInst>(Inst)) {
+ MemTypeResetInsts.push_back(&Inst);
+ }
+ }
+ }
+
+ // byval arguments also need their types reset (they're new stack memory,
+ // just like allocas).
+ for (auto &A : F.args())
+ if (A.hasByValAttr())
+ MemTypeResetInsts.push_back(&A);
+
+ // We have collected all loads and stores, and know for what TBAA nodes we
+ // need to generate type descriptors.
+
+ Module &M = *F.getParent();
+ TypeDescriptorsMapTy TypeDescriptors;
+ TypeNameMapTy TypeNames;
+ for (const MDNode *MD : TBAAMetadata) {
+ if (TypeDescriptors.count(MD))
+ continue;
+
+ if (!generateTypeDescriptor(MD, TypeDescriptors, TypeNames, M))
+ return Res; // Giving up.
+
+ Res = true;
+ }
+
+ Value *ShadowBase = nullptr, *AppMemMask = nullptr;
+ for (auto &MA : MemoryAccesses)
+ Res |= instrumentMemoryAccess(MA.first, MA.second, ShadowBase, AppMemMask,
+ SanitizeFunction, TypeDescriptors, DL);
+
+ for (auto Inst : MemTypeResetInsts)
+ Res |= instrumentMemInst(Inst, ShadowBase, AppMemMask, DL);
+
+ return Res;
+}
+
+static Value *ConvertToShadowDataInt(IRBuilder<> &IRB, Value *Ptr,
+ Type *IntptrTy, uint64_t PtrShift,
+ Value *ShadowBase, Value *AppMemMask) {
+ return IRB.CreateAdd(
+ IRB.CreateShl(
+ IRB.CreateAnd(IRB.CreatePtrToInt(Ptr, IntptrTy, "app.ptr.int"),
+ AppMemMask, "app.ptr.masked"),
+ PtrShift, "app.ptr.shifted"),
+ ShadowBase, "shadow.ptr.int");
+}
+
+bool TypeSanitizer::instrumentWithShadowUpdate(
+ IRBuilder<> &IRB, const MDNode *TBAAMD, Value *Ptr, uint64_t AccessSize,
+ bool IsRead, bool IsWrite, Value *&ShadowBase, Value *&AppMemMask,
+ bool ForceSetType, bool SanitizeFunction,
+ TypeDescriptorsMapTy &TypeDescriptors, const DataLayout &DL) {
+ if (!ShadowBase)
+ ShadowBase = getShadowBase(*IRB.GetInsertBlock()->getParent());
+ if (!AppMemMask)
+ AppMemMask = getAppMemMask(*IRB.GetInsertBlock()->getParent());
+
+ Constant *TDGV;
+ if (TBAAMD)
+ TDGV = TypeDescriptors[TBAAMD];
+ else
+ TDGV = Constant::getNullValue(IRB.getPtrTy());
+
+ Value *TD = IRB.CreateBitCast(TDGV, IRB.getPtrTy());
+
+ Value *ShadowDataInt = ConvertToShadowDataInt(IRB, Ptr, IntptrTy, PtrShift,
+ ShadowBase, AppMemMask);
+ Type *Int8PtrPtrTy = IRB.getPtrTy()->getPointerTo();
+ Value *ShadowData =
+ IRB.CreateIntToPtr(ShadowDataInt, Int8PtrPtrTy, "shadow.ptr");
+
+ auto SetType = [&]() {
+ IRB.CreateStore(TD, ShadowData);
+
+ // Now fill the remainder of the shadow memory corresponding to the
+ // remainder of the the bytes of the type with a bad type descriptor.
+ for (uint64_t i = 1; i < AccessSize; ++i) {
+ Value *BadShadowData = IRB.CreateIntToPtr(
+ IRB.CreateAdd(ShadowDataInt,
+ ConstantInt::get(IntptrTy, i << PtrShift),
+ "shadow.byte." + Twine(i) + ".offset"),
+ Int8PtrPtrTy, "shadow.byte." + Twine(i) + ".ptr");
+
+ // This is the TD value, -i, which is used to indicate that the byte is
+ // i bytes after the first byte of the type.
+ Value *BadTD =
+ IRB.CreateIntToPtr(ConstantInt::getSigned(IntptrTy, -i),
+ IRB.getPtrTy(), "bad.descriptor" + Twine(i));
+ IRB.CreateStore(BadTD, BadShadowData);
+ }
+ };
+
+ if (!ForceSetType && (!ClWritesAlwaysSetType || IsRead)) {
+ // We need to check the type here. If the type is unknown, then the read
+ // sets the type. If the type is known, then it is checked. If the type
+ // doesn't match, then we call the runtime (which may yet determine that
+ // the mismatch is okay).
+ LLVMContext &C = IRB.getContext();
+ MDNode *UnlikelyBW = MDBuilder(C).createBranchWeights(1, 100000);
+
+ Constant *Flags =
+ ConstantInt::get(OrdTy, (int)IsRead | (((int)IsWrite) << 1));
+
+ Value *LoadedTD =
+ IRB.CreateLoad(IRB.getPtrTy(), ShadowData, "shadow.desc");
+ if (SanitizeFunction) {
+ Value *BadTDCmp = IRB.CreateICmpNE(LoadedTD, TD, "bad.desc");
+ Instruction *BadTDTerm, *GoodTDTerm;
+ SplitBlockAndInsertIfThenElse(BadTDCmp, &*IRB.GetInsertPoint(),
+ &BadTDTerm, &GoodTDTerm, UnlikelyBW);
+ IRB.SetInsertPoint(BadTDTerm);
+
+ // We now know that the types did not match (we're on the slow path). If
+ // the type is unknown, then set it.
+ Value *NullTDCmp = IRB.CreateIsNull(LoadedTD);
+ Instruction *NullTDTerm, *MismatchTerm;
+ SplitBlockAndInsertIfThenElse(NullTDCmp, &*IRB.GetInsertPoint(),
+ &NullTDTerm, &MismatchTerm);
+
+ // If the type is unknown, then set the type.
+ IRB.SetInsertPoint(NullTDTerm);
+
+ // We're about to set the type. Make sure that all bytes in the value are
+ // also of unknown type.
+ Value *Size = ConstantInt::get(OrdTy, AccessSize);
+ Value *NotAllUnkTD = IRB.getFalse();
+ for (uint64_t i = 1; i < AccessSize; ++i) {
+ Value *UnkShadowData = IRB.CreateIntToPtr(
+ IRB.CreateAdd(ShadowDataInt,
+ ConstantInt::get(IntptrTy, i << PtrShift)),
+ Int8PtrPtrTy);
+ Value *ILdTD = IRB.CreateLoad(IRB.getPtrTy(), UnkShadowData);
+ NotAllUnkTD = IRB.CreateOr(NotAllUnkTD, IRB.CreateIsNotNull(ILdTD));
+ }
+
+ Instruction *BeforeSetType = &*IRB.GetInsertPoint();
+ Instruction *BadUTDTerm = SplitBlockAndInsertIfThen(
+ NotAllUnkTD, BeforeSetType, false, UnlikelyBW);
+ IRB.SetInsertPoint(BadUTDTerm);
+ IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()),
+ Size, (Value *)TD, (Value *)Flags});
+
+ IRB.SetInsertPoint(BeforeSetType);
+ SetType();
+
+ // We have a non-trivial mismatch. Call the runtime.
+ IRB.SetInsertPoint(MismatchTerm);
+ IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()),
+ Size, (Value *)TD, (Value *)Flags});
+
+ // We appear to have the right type. Make sure that all other bytes in
+ // the type are still marked as interior bytes. If not, call the runtime.
+ IRB.SetInsertPoint(GoodTDTerm);
+ Value *NotAllBadTD = IRB.getFalse();
+ for (uint64_t i = 1; i < AccessSize; ++i) {
+ Value *BadShadowData = IRB.CreateIntToPtr(
+ IRB.CreateAdd(ShadowDataInt,
+ ConstantInt::get(IntptrTy, i << PtrShift)),
+ Int8PtrPtrTy);
+ Value *ILdTD = IRB.CreatePtrToInt(
+ IRB.CreateLoad(IRB.getPtrTy(), BadShadowData), IntptrTy);
+ NotAllBadTD = IRB.CreateOr(
+ NotAllBadTD,
+ IRB.CreateICmpSGE(ILdTD, ConstantInt::get(IntptrTy, 0)));
+ }
+
+ Instruction *BadITDTerm = SplitBlockAndInsertIfThen(
+ NotAllBadTD, &*IRB.GetInsertPoint(), false, UnlikelyBW);
+ IRB.SetInsertPoint(BadITDTerm);
+ IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()),
+ Size, (Value *)TD, (Value *)Flags});
+ } else {
+ // If we're not sanitizing this function, then we only care whether we
+ // need to *set* the type.
+ Value *NullTDCmp = IRB.CreateIsNull(LoadedTD, "desc.set");
+ Instruction *NullTDTerm = SplitBlockAndInsertIfThen(
+ NullTDCmp, &*IRB.GetInsertPoint(), false, UnlikelyBW);
+ IRB.SetInsertPoint(NullTDTerm);
+ NullTDTerm->getParent()->setName("set.type");
+ SetType();
+ }
+ } else if (ForceSetType || IsWrite) {
+ // In the mode where writes always set the type, for a write (which does
+ // not also read), we just set the type.
+ SetType();
+ }
+
+ return true;
+}
+
+bool TypeSanitizer::instrumentMemoryAccess(
+ Instruction *I, MemoryLocation &MLoc, Value *&ShadowBase,
+ Value *&AppMemMask, bool SanitizeFunction,
+ TypeDescriptorsMapTy &TypeDescriptors, const DataLayout &DL) {
+ IRBuilder<> IRB(I);
+ assert(MLoc.Size.isPrecise());
+ if (instrumentWithShadowUpdate(
+ IRB, MLoc.AATags.TBAA, const_cast<Value *>(MLoc.Ptr),
+ MLoc.Size.getValue(), I->mayReadFromMemory(), I->mayWriteToMemory(),
+ ShadowBase, AppMemMask, false, SanitizeFunction, TypeDescriptors,
+ DL)) {
+ ++NumInstrumentedAccesses;
+ return true;
+ }
+
+ return false;
+}
+
+// Memory-related intrinsics/instructions reset the type of the destination
+// memory (including allocas and byval arguments).
+bool TypeSanitizer::instrumentMemInst(Value *V, Value *&ShadowBase,
+ Value *&AppMemMask,
+ const DataLayout &DL) {
+ BasicBlock::iterator IP;
+ BasicBlock *BB;
+ Function *F;
+
+ if (auto *I = dyn_cast<Instruction>(V)) {
+ IP = BasicBlock::iterator(I);
+ BB = I->getParent();
+ F = BB->getParent();
+ } else {
+ auto *A = cast<Argument>(V);
+ F = A->getParent();
+ BB = &F->getEntryBlock();
+ IP = BB->getFirstInsertionPt();
+
+ if (auto *I = cast_or_null<Instruction>(ShadowBase)) {
+ if (IP->comesBefore(I))
+ IP = I->getNextNode()->getIterator();
+ }
+ if (auto *I = cast_or_null<Instruction>(AppMemMask)) {
+ if (IP->comesBefore(I))
+ IP = I->getNextNode()->getIterator();
+ }
+ }
+
+ Value *Dest, *Size, *Src = nullptr;
+ bool NeedsMemMove = false;
+ IRBuilder<> IRB(BB, IP);
+
+ if (auto *A = dyn_cast<Argument>(V)) {
+ assert(A->hasByValAttr() && "Type reset for non-byval argument?");
+
+ Dest = A;
+ Size =
+ ConstantInt::get(IntptrTy, DL.getTypeAllocSize(A->getParamByValType()));
+ } else {
+ auto *I = cast<Instruction>(V);
+ if (auto *MI = dyn_cast<MemIntrinsic>(I)) {
+ if (MI->getDestAddressSpace() != 0)
+ return false;
+
+ Dest = MI->getDest();
+ Size = MI->getLength();
+
+ if (auto *MTI = dyn_cast<MemTransferInst>(MI)) {
+ if (MTI->getSourceAddressSpace() == 0) {
+ Src = MTI->getSource();
+ NeedsMemMove = isa<MemMoveInst>(MTI);
+ }
+ }
+ } else if (auto *II = dyn_cast<IntrinsicInst>(I)) {
+ if (II->getIntrinsicID() != Intrinsic::lifetime_start &&
+ II->getIntrinsicID() != Intrinsic::lifetime_end)
+ return false;
+
+ Size = II->getArgOperand(0);
+ Dest = II->getArgOperand(1);
+ } else if (auto *AI = dyn_cast<AllocaInst>(I)) {
+ // We need to clear the types for new stack allocations (or else we might
+ // read stale type information from a previous function execution).
+
+ IRB.SetInsertPoint(&*std::next(BasicBlock::iterator(I)));
+ IRB.SetInstDebugLocation(I);
+
+ Size = IRB.CreateMul(
+ IRB.CreateZExtOrTrunc(AI->getArraySize(), IntptrTy),
+ ConstantInt::get(IntptrTy,
+ DL.getTypeAllocSize(AI->getAllocatedType())));
+ Dest = I;
+ } else {
+ return false;
+ }
+ }
+
+ if (!ShadowBase)
+ ShadowBase = getShadowBase(*F);
+ if (!AppMemMask)
+ AppMemMask = getAppMemMask(*F);
+
+ Value *ShadowDataInt = IRB.CreateAdd(
+ IRB.CreateShl(
+ IRB.CreateAnd(IRB.CreatePtrToInt(Dest, IntptrTy), AppMemMask),
+ PtrShift),
+ ShadowBase);
+ Value *ShadowData = IRB.CreateIntToPtr(ShadowDataInt, IRB.getPtrTy());
+
+ if (!Src) {
+ IRB.CreateMemSet(ShadowData, IRB.getInt8(0), IRB.CreateShl(Size, PtrShift),
+ Align(1u << PtrShift));
+ return true;
+ }
+
+ Value *SrcShadowDataInt = IRB.CreateAdd(
+ IRB.CreateShl(
+ IRB.CreateAnd(IRB.CreatePtrToInt(Src, IntptrTy), AppMemMask),
+ PtrShift),
+ ShadowBase);
+ Value *SrcShadowData =
+ IRB.CreateIntToPtr(SrcShadowDataInt, IRB.getPtrTy());
+
+ if (NeedsMemMove) {
+ IRB.CreateMemMove(ShadowData, Align(1u << PtrShift), SrcShadowData,
+ Align(1u << PtrShift), IRB.CreateShl(Size, PtrShift));
+ } else {
+ IRB.CreateMemCpy(ShadowData, Align(1u << PtrShift), SrcShadowData,
+ Align(1u << PtrShift), IRB.CreateShl(Size, PtrShift));
+ }
+
+ return true;
+}
+
+PreservedAnalyses TypeSanitizerPass::run(Function &F,
+ FunctionAnalysisManager &FAM) {
+ TypeSanitizer TySan(*F.getParent());
+ TySan.run(F, FAM.getResult<TargetLibraryAnalysis>(F));
+ return PreservedAnalyses::none();
+}
+
+PreservedAnalyses ModuleTypeSanitizerPass::run(Module &M,
+ ModuleAnalysisManager &AM) {
+ insertModuleCtor(M);
+ return PreservedAnalyses::none();
+}
diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
index f5abed0dd51786..9e60690009dcf6 100644
--- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -955,6 +955,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
case Attribute::SanitizeAddress:
case Attribute::SanitizeMemory:
case Attribute::SanitizeThread:
+ case Attribute::SanitizeType:
case Attribute::SanitizeHWAddress:
case Attribute::SanitizeMemTag:
case Attribute::SpeculativeLoadHardening:
diff --git a/llvm/test/Instrumentation/TypeSanitizer/access-with-offfset.ll b/llvm/test/Instrumentation/TypeSanitizer/access-with-offfset.ll
new file mode 100644
index 00000000000000..297ee83527b5c1
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/access-with-offfset.ll
@@ -0,0 +1,71 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+;.
+; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2FC_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [18 x i8] } { i64 2, i64 0, [18 x i8] c"Simple C/C++ TBAA\00" }, comdat
+; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2fC_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat
+; CHECK: @[[__TYSAN_V1_ANY_20POINTER:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [12 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [12 x i8] c"any pointer\00" }, comdat
+; CHECK: @[[__TYSAN_V1_ANY_20POINTER_O_0:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_any_20pointer, ptr @__tysan_v1_any_20pointer, i64 0 }, comdat
+; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [5 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2fC_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_any_20pointer, ptr @__tysan_v1_any_20pointer_o_0], section "llvm.metadata"
+; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+;.
+define ptr @test_load_offset(ptr %argv) {
+; CHECK-LABEL: @test_load_offset(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 4
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 4
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 0, [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[DESC_SET:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[DESC_SET]], label [[SET_TYPE:%.*]], label [[TMP0:%.*]], !prof [[PROF0:![0-9]+]]
+; CHECK: set.type:
+; CHECK-NEXT: store ptr @__tysan_v1_any_20pointer_o_0, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_4_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 32
+; CHECK-NEXT: [[SHADOW_BYTE_4_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_4_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -4 to ptr), ptr [[SHADOW_BYTE_4_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_5_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 40
+; CHECK-NEXT: [[SHADOW_BYTE_5_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_5_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -5 to ptr), ptr [[SHADOW_BYTE_5_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_6_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 48
+; CHECK-NEXT: [[SHADOW_BYTE_6_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_6_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -6 to ptr), ptr [[SHADOW_BYTE_6_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_7_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 56
+; CHECK-NEXT: [[SHADOW_BYTE_7_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_7_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -7 to ptr), ptr [[SHADOW_BYTE_7_PTR]], align 8
+; CHECK-NEXT: br label [[TMP0]]
+; CHECK: 0:
+; CHECK-NEXT: [[L:%.*]] = load ptr, ptr null, align 8, !tbaa [[TBAA1:![0-9]+]]
+; CHECK-NEXT: ret ptr [[L]]
+;
+entry:
+ %l = load ptr, ptr null, align 8, !tbaa !0
+ ret ptr %l
+}
+
+!0 = !{!1, !1, i64 0}
+!1 = !{!"any pointer", !2, i64 0}
+!2 = !{!"omnipotent char", !3, i64 0}
+!3 = !{!"Simple C/C++ TBAA"}
+;.
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind }
+;.
+; CHECK: [[PROF0]] = !{!"branch_weights", i32 1, i32 100000}
+; CHECK: [[TBAA1]] = !{!2, !2, i64 0}
+; CHECK: [[META2:![0-9]+]] = !{!"any pointer", !3, i64 0}
+; CHECK: [[META3:![0-9]+]] = !{!"omnipotent char", !4, i64 0}
+; CHECK: [[META4:![0-9]+]] = !{!"Simple C/C++ TBAA"}
+;.
diff --git a/llvm/test/Instrumentation/TypeSanitizer/alloca.ll b/llvm/test/Instrumentation/TypeSanitizer/alloca.ll
new file mode 100644
index 00000000000000..94098bd8a1739a
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/alloca.ll
@@ -0,0 +1,29 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test basic type sanitizer instrumentation.
+;
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+declare void @alloca_test_use(ptr)
+
+define void @alloca_test() sanitize_type {
+; CHECK-LABEL: @alloca_test(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[X:%.*]] = alloca [10 x i8], align 1
+; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[X]] to i64
+; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[TMP4]], i8 0, i64 80, i1 false)
+; CHECK-NEXT: call void @alloca_test_use(ptr [[X]])
+; CHECK-NEXT: ret void
+;
+entry:
+ %x = alloca [10 x i8], align 1
+ call void @alloca_test_use([10 x i8]* %x)
+ ret void
+}
diff --git a/llvm/test/Instrumentation/TypeSanitizer/anon.ll b/llvm/test/Instrumentation/TypeSanitizer/anon.ll
new file mode 100644
index 00000000000000..70f5dcefde64c1
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/anon.ll
@@ -0,0 +1,283 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
+; Test basic type sanitizer instrumentation.
+;
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat
+; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat
+; CHECK: @[[__TYSAN_V1_INT:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat
+; CHECK: @[[__TYSAN_V1___ZTSN12__GLOBAL____N__11ZE:[a-zA-Z0-9_$"\\.-]+]] = internal constant { i64, i64, ptr, i64, [23 x i8] } { i64 2, i64 1, ptr @__tysan_v1_int, i64 24, [23 x i8] c"_ZTSN12_GLOBAL__N_11zE\00" }
+; CHECK: @[[__TYSAN_V1___ZTSN12__GLOBAL____N__11ZE_O_24:[a-zA-Z0-9_$"\\.-]+]] = internal constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1___ZTSN12__GLOBAL____N__11zE, ptr @__tysan_v1_int, i64 24 }
+; CHECK: @[[__TYSAN_V1___ZTS1YIN12__GLOBAL____N__11ZEE:[a-zA-Z0-9_$"\\.-]+]] = internal constant { i64, i64, ptr, i64, [27 x i8] } { i64 2, i64 1, ptr @__tysan_v1_int, i64 24, [27 x i8] c"_ZTS1yIN12_GLOBAL__N_11zEE\00" }
+; CHECK: @[[__TYSAN_V1___ZTS1YIN12__GLOBAL____N__11ZEE_O_24:[a-zA-Z0-9_$"\\.-]+]] = internal constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE, ptr @__tysan_v1_int, i64 24 }
+; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[__TYSAN_V1_____ANONYMOUS__027D9E575C5D34CB5D60D6A1D6276F95:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [1 x i8] } { i64 2, i64 1, ptr @__tysan_v1_int, i64 24, [1 x i8] zeroinitializer }, comdat
+; CHECK: @[[__TYSAN_V1_____ANONYMOUS__027D9E575C5D34CB5D60D6A1D6276F95_O_24:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95, ptr @__tysan_v1_int, i64 24 }, comdat
+; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [6 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24], section "llvm.metadata"
+
+
+define void @test_anon_ns(ptr %a, ptr %b) sanitize_type {
+; CHECK-LABEL: @test_anon_ns(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], @__tysan_v1___ZTSN12__GLOBAL____N__11zE_o_24
+; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0:![0-9]+]]
+; CHECK: 0:
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]]
+; CHECK: 2:
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
+; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null
+; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]]
+; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr
+; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8
+; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null
+; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]]
+; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr
+; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8
+; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null
+; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]]
+; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]]
+; CHECK: 18:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTSN12__GLOBAL____N__11zE_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP19]]
+; CHECK: 19:
+; CHECK-NEXT: store ptr @__tysan_v1___ZTSN12__GLOBAL____N__11zE_o_24, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: br label [[TMP21:%.*]]
+; CHECK: 20:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTSN12__GLOBAL____N__11zE_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP21]]
+; CHECK: 21:
+; CHECK-NEXT: br label [[TMP43:%.*]]
+; CHECK: 22:
+; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr
+; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8
+; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64
+; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0
+; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]]
+; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr
+; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8
+; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64
+; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0
+; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]]
+; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr
+; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8
+; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64
+; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0
+; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]]
+; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]]
+; CHECK: 41:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTSN12__GLOBAL____N__11zE_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP42]]
+; CHECK: 42:
+; CHECK-NEXT: br label [[TMP43]]
+; CHECK: 43:
+; CHECK-NEXT: store i32 42, ptr [[A]], align 4, !tbaa [[TBAA1:![0-9]+]]
+; CHECK-NEXT: [[APP_PTR_INT1:%.*]] = ptrtoint ptr [[B:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED2:%.*]] = and i64 [[APP_PTR_INT1]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED3:%.*]] = shl i64 [[APP_PTR_MASKED2]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT4:%.*]] = add i64 [[APP_PTR_SHIFTED3]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR5:%.*]] = inttoptr i64 [[SHADOW_PTR_INT4]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC6:%.*]] = load ptr, ptr [[SHADOW_PTR5]], align 8
+; CHECK-NEXT: [[BAD_DESC7:%.*]] = icmp ne ptr [[SHADOW_DESC6]], @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE_o_24
+; CHECK-NEXT: br i1 [[BAD_DESC7]], label [[TMP44:%.*]], label [[TMP66:%.*]], !prof [[PROF0]]
+; CHECK: 44:
+; CHECK-NEXT: [[TMP45:%.*]] = icmp eq ptr [[SHADOW_DESC6]], null
+; CHECK-NEXT: br i1 [[TMP45]], label [[TMP46:%.*]], label [[TMP64:%.*]]
+; CHECK: 46:
+; CHECK-NEXT: [[TMP47:%.*]] = add i64 [[SHADOW_PTR_INT4]], 8
+; CHECK-NEXT: [[TMP48:%.*]] = inttoptr i64 [[TMP47]] to ptr
+; CHECK-NEXT: [[TMP49:%.*]] = load ptr, ptr [[TMP48]], align 8
+; CHECK-NEXT: [[TMP50:%.*]] = icmp ne ptr [[TMP49]], null
+; CHECK-NEXT: [[TMP51:%.*]] = or i1 false, [[TMP50]]
+; CHECK-NEXT: [[TMP52:%.*]] = add i64 [[SHADOW_PTR_INT4]], 16
+; CHECK-NEXT: [[TMP53:%.*]] = inttoptr i64 [[TMP52]] to ptr
+; CHECK-NEXT: [[TMP54:%.*]] = load ptr, ptr [[TMP53]], align 8
+; CHECK-NEXT: [[TMP55:%.*]] = icmp ne ptr [[TMP54]], null
+; CHECK-NEXT: [[TMP56:%.*]] = or i1 [[TMP51]], [[TMP55]]
+; CHECK-NEXT: [[TMP57:%.*]] = add i64 [[SHADOW_PTR_INT4]], 24
+; CHECK-NEXT: [[TMP58:%.*]] = inttoptr i64 [[TMP57]] to ptr
+; CHECK-NEXT: [[TMP59:%.*]] = load ptr, ptr [[TMP58]], align 8
+; CHECK-NEXT: [[TMP60:%.*]] = icmp ne ptr [[TMP59]], null
+; CHECK-NEXT: [[TMP61:%.*]] = or i1 [[TMP56]], [[TMP60]]
+; CHECK-NEXT: br i1 [[TMP61]], label [[TMP62:%.*]], label [[TMP63:%.*]], !prof [[PROF0]]
+; CHECK: 62:
+; CHECK-NEXT: call void @__tysan_check(ptr [[B]], i32 4, ptr @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP63]]
+; CHECK: 63:
+; CHECK-NEXT: store ptr @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE_o_24, ptr [[SHADOW_PTR5]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET8:%.*]] = add i64 [[SHADOW_PTR_INT4]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR9:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET8]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR9]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET10:%.*]] = add i64 [[SHADOW_PTR_INT4]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR11:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET10]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR11]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET12:%.*]] = add i64 [[SHADOW_PTR_INT4]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR13:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET12]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR13]], align 8
+; CHECK-NEXT: br label [[TMP65:%.*]]
+; CHECK: 64:
+; CHECK-NEXT: call void @__tysan_check(ptr [[B]], i32 4, ptr @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP65]]
+; CHECK: 65:
+; CHECK-NEXT: br label [[TMP87:%.*]]
+; CHECK: 66:
+; CHECK-NEXT: [[TMP67:%.*]] = add i64 [[SHADOW_PTR_INT4]], 8
+; CHECK-NEXT: [[TMP68:%.*]] = inttoptr i64 [[TMP67]] to ptr
+; CHECK-NEXT: [[TMP69:%.*]] = load ptr, ptr [[TMP68]], align 8
+; CHECK-NEXT: [[TMP70:%.*]] = ptrtoint ptr [[TMP69]] to i64
+; CHECK-NEXT: [[TMP71:%.*]] = icmp sge i64 [[TMP70]], 0
+; CHECK-NEXT: [[TMP72:%.*]] = or i1 false, [[TMP71]]
+; CHECK-NEXT: [[TMP73:%.*]] = add i64 [[SHADOW_PTR_INT4]], 16
+; CHECK-NEXT: [[TMP74:%.*]] = inttoptr i64 [[TMP73]] to ptr
+; CHECK-NEXT: [[TMP75:%.*]] = load ptr, ptr [[TMP74]], align 8
+; CHECK-NEXT: [[TMP76:%.*]] = ptrtoint ptr [[TMP75]] to i64
+; CHECK-NEXT: [[TMP77:%.*]] = icmp sge i64 [[TMP76]], 0
+; CHECK-NEXT: [[TMP78:%.*]] = or i1 [[TMP72]], [[TMP77]]
+; CHECK-NEXT: [[TMP79:%.*]] = add i64 [[SHADOW_PTR_INT4]], 24
+; CHECK-NEXT: [[TMP80:%.*]] = inttoptr i64 [[TMP79]] to ptr
+; CHECK-NEXT: [[TMP81:%.*]] = load ptr, ptr [[TMP80]], align 8
+; CHECK-NEXT: [[TMP82:%.*]] = ptrtoint ptr [[TMP81]] to i64
+; CHECK-NEXT: [[TMP83:%.*]] = icmp sge i64 [[TMP82]], 0
+; CHECK-NEXT: [[TMP84:%.*]] = or i1 [[TMP78]], [[TMP83]]
+; CHECK-NEXT: br i1 [[TMP84]], label [[TMP85:%.*]], label [[TMP86:%.*]], !prof [[PROF0]]
+; CHECK: 85:
+; CHECK-NEXT: call void @__tysan_check(ptr [[B]], i32 4, ptr @__tysan_v1___ZTS1yIN12__GLOBAL____N__11zEE_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP86]]
+; CHECK: 86:
+; CHECK-NEXT: br label [[TMP87]]
+; CHECK: 87:
+; CHECK-NEXT: store i32 43, ptr [[B]], align 4, !tbaa [[TBAA6:![0-9]+]]
+; CHECK-NEXT: ret void
+;
+entry:
+ store i32 42, ptr %a, align 4, !tbaa !8
+ store i32 43, ptr %b, align 4, !tbaa !10
+ ret void
+
+}
+
+define void @test_anon_type(ptr %a) sanitize_type {
+; CHECK-LABEL: @test_anon_type(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24
+; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0]]
+; CHECK: 0:
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]]
+; CHECK: 2:
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
+; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null
+; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]]
+; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr
+; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8
+; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null
+; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]]
+; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr
+; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8
+; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null
+; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]]
+; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]]
+; CHECK: 18:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP19]]
+; CHECK: 19:
+; CHECK-NEXT: store ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: br label [[TMP21:%.*]]
+; CHECK: 20:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP21]]
+; CHECK: 21:
+; CHECK-NEXT: br label [[TMP43:%.*]]
+; CHECK: 22:
+; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr
+; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8
+; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64
+; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0
+; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]]
+; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr
+; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8
+; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64
+; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0
+; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]]
+; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr
+; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8
+; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64
+; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0
+; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]]
+; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]]
+; CHECK: 41:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95_o_24, i32 2)
+; CHECK-NEXT: br label [[TMP42]]
+; CHECK: 42:
+; CHECK-NEXT: br label [[TMP43]]
+; CHECK: 43:
+; CHECK-NEXT: store i32 42, ptr [[A]], align 4, !tbaa [[TBAA8:![0-9]+]]
+; CHECK-NEXT: ret void
+;
+entry:
+ store i32 42, ptr %a, align 4, !tbaa !12
+ ret void
+
+}
+
+!0 = !{!"Simple C++ TBAA"}
+!1 = !{!"omnipotent char", !0, i64 0}
+!2 = !{!"int", !1, i64 0}
+!7 = !{!"_ZTSN12_GLOBAL__N_11zE", !2, i64 24}
+!8 = !{!7, !2, i64 24}
+!9 = !{!"_ZTS1yIN12_GLOBAL__N_11zEE", !2, i64 24}
+!10 = !{!9, !2, i64 24}
+!11 = !{!"", !2, i64 24}
+!12 = !{!11, !2, i64 24}
diff --git a/llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll b/llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll
new file mode 100644
index 00000000000000..7f25e36e6660e8
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll
@@ -0,0 +1,93 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs
+; Test basic type sanitizer instrumentation.
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat
+; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat
+; CHECK: @[[__TYSAN_V1_INT:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat
+; CHECK: @[[__TYSAN_V1_INT_O_0:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_int, ptr @__tysan_v1_int, i64 0 }, comdat
+; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [5 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int, ptr @__tysan_v1_int_o_0], section "llvm.metadata"
+; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+;
+define i32 @test_load_nsan(ptr %a) {
+; CHECK-LABEL: @test_load_nsan(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[DESC_SET:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[DESC_SET]], label [[SET_TYPE:%.*]], label [[TMP0:%.*]], !prof [[PROF0:![0-9]+]]
+; CHECK: set.type:
+; CHECK-NEXT: store ptr @__tysan_v1_int_o_0, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: br label [[TMP0]]
+; CHECK: 0:
+; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A]], align 4, !tbaa [[TBAA1:![0-9]+]]
+; CHECK-NEXT: ret i32 [[TMP1]]
+;
+entry:
+ %tmp1 = load i32, ptr %a, align 4, !tbaa !3
+ ret i32 %tmp1
+}
+
+define void @test_store_nsan(ptr %a) {
+; CHECK-LABEL: @test_store_nsan(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[DESC_SET:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[DESC_SET]], label [[SET_TYPE:%.*]], label [[TMP0:%.*]], !prof [[PROF0]]
+; CHECK: set.type:
+; CHECK-NEXT: store ptr @__tysan_v1_int_o_0, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: br label [[TMP0]]
+; CHECK: 0:
+; CHECK-NEXT: store i32 42, ptr [[A]], align 4, !tbaa [[TBAA1]]
+; CHECK-NEXT: ret void
+;
+entry:
+ store i32 42, ptr %a, align 4, !tbaa !3
+ ret void
+}
+
+; CHECK-LABEL: @tysan.module_ctor(
+; CHECK-NEXT: call void @__tysan_init()
+; CHECK-NEXT: ret void
+;
+; CHECK: [[PROF0]] = !{!"branch_weights", i32 1, i32 100000}
+
+!0 = !{!"Simple C++ TBAA"}
+!1 = !{!"omnipotent char", !0, i64 0}
+!2 = !{!"int", !1, i64 0}
+!3 = !{!2, !2, i64 0}
diff --git a/llvm/test/Instrumentation/TypeSanitizer/basic.ll b/llvm/test/Instrumentation/TypeSanitizer/basic.ll
new file mode 100644
index 00000000000000..132df722e83c25
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/basic.ll
@@ -0,0 +1,214 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
+; Test basic type sanitizer instrumentation.
+;
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+
+; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat
+; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat
+; CHECK: @[[__TYSAN_V1_INT:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat
+; CHECK: @[[__TYSAN_V1_INT_O_0:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_int, ptr @__tysan_v1_int, i64 0 }, comdat
+; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[__TYSAN_V1___ZTS1X:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, ptr, i64, [7 x i8] } { i64 2, i64 2, ptr @__tysan_v1_int, i64 0, ptr @__tysan_v1_int, i64 4, [7 x i8] c"_ZTS1x\00" }, comdat
+; CHECK: @[[__TYSAN_V1___ZTS1V:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, ptr, i64, ptr, i64, [7 x i8] } { i64 2, i64 3, ptr @__tysan_v1_int, i64 8, ptr @__tysan_v1_int, i64 12, ptr @__tysan_v1___ZTS1x, i64 16, [7 x i8] c"_ZTS1v\00" }, comdat
+; CHECK: @[[__TYSAN_V1___ZTS1V_O_12:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1___ZTS1v, ptr @__tysan_v1_int, i64 12 }, comdat
+; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [8 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int, ptr @__tysan_v1_int_o_0, ptr @__tysan_v1___ZTS1x, ptr @__tysan_v1___ZTS1v, ptr @__tysan_v1___ZTS1v_o_12], section "llvm.metadata"
+
+define i32 @test_load(ptr %a) sanitize_type {
+; CHECK-LABEL: @test_load(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], @__tysan_v1_int_o_0
+; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0:![0-9]+]]
+; CHECK: 0:
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]]
+; CHECK: 2:
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
+; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null
+; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]]
+; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr
+; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8
+; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null
+; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]]
+; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr
+; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8
+; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null
+; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]]
+; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]]
+; CHECK: 18:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_int_o_0, i32 1)
+; CHECK-NEXT: br label [[TMP19]]
+; CHECK: 19:
+; CHECK-NEXT: store ptr @__tysan_v1_int_o_0, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: br label [[TMP21:%.*]]
+; CHECK: 20:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_int_o_0, i32 1)
+; CHECK-NEXT: br label [[TMP21]]
+; CHECK: 21:
+; CHECK-NEXT: br label [[TMP43:%.*]]
+; CHECK: 22:
+; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr
+; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8
+; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64
+; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0
+; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]]
+; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr
+; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8
+; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64
+; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0
+; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]]
+; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr
+; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8
+; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64
+; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0
+; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]]
+; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]]
+; CHECK: 41:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1_int_o_0, i32 1)
+; CHECK-NEXT: br label [[TMP42]]
+; CHECK: 42:
+; CHECK-NEXT: br label [[TMP43]]
+; CHECK: 43:
+; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A]], align 4, !tbaa [[TBAA1:![0-9]+]]
+; CHECK-NEXT: ret i32 [[TMP1]]
+;
+entry:
+ %tmp1 = load i32, ptr %a, align 4, !tbaa !3
+ ret i32 %tmp1
+}
+
+define void @test_store(ptr %a) sanitize_type {
+; CHECK-LABEL: @test_store(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], @__tysan_v1___ZTS1v_o_12
+; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0]]
+; CHECK: 0:
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]]
+; CHECK: 2:
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
+; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null
+; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]]
+; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr
+; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8
+; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null
+; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]]
+; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr
+; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8
+; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null
+; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]]
+; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]]
+; CHECK: 18:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTS1v_o_12, i32 2)
+; CHECK-NEXT: br label [[TMP19]]
+; CHECK: 19:
+; CHECK-NEXT: store ptr @__tysan_v1___ZTS1v_o_12, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: br label [[TMP21:%.*]]
+; CHECK: 20:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTS1v_o_12, i32 2)
+; CHECK-NEXT: br label [[TMP21]]
+; CHECK: 21:
+; CHECK-NEXT: br label [[TMP43:%.*]]
+; CHECK: 22:
+; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr
+; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8
+; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64
+; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0
+; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]]
+; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr
+; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8
+; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64
+; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0
+; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]]
+; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr
+; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8
+; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64
+; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0
+; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]]
+; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]]
+; CHECK: 41:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr @__tysan_v1___ZTS1v_o_12, i32 2)
+; CHECK-NEXT: br label [[TMP42]]
+; CHECK: 42:
+; CHECK-NEXT: br label [[TMP43]]
+; CHECK: 43:
+; CHECK-NEXT: store i32 42, ptr [[A]], align 4, !tbaa [[TBAA5:![0-9]+]]
+; CHECK-NEXT: ret void
+;
+entry:
+ store i32 42, ptr %a, align 4, !tbaa !6
+ ret void
+}
+
+!0 = !{!"Simple C++ TBAA"}
+!1 = !{!"omnipotent char", !0, i64 0}
+!2 = !{!"int", !1, i64 0}
+!3 = !{!2, !2, i64 0}
+!4 = !{!"_ZTS1x", !2, i64 0, !2, i64 4}
+!5 = !{!"_ZTS1v", !2, i64 8, !2, i64 12, !4, i64 16}
+!6 = !{!5, !2, i64 12}
+;.
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { sanitize_type }
+; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind }
+;.
+; CHECK: [[PROF0]] = !{!"branch_weights", i32 1, i32 100000}
+; CHECK: [[TBAA1]] = !{!2, !2, i64 0}
+; CHECK: [[META2:![0-9]+]] = !{!"int", !3, i64 0}
+; CHECK: [[META3:![0-9]+]] = !{!"omnipotent char", !4, i64 0}
+; CHECK: [[META4:![0-9]+]] = !{!"Simple C++ TBAA"}
+; CHECK: [[TBAA5]] = !{!6, !2, i64 12}
+; CHECK: [[META6:![0-9]+]] = !{!"_ZTS1v", !2, i64 8, !2, i64 12, !7, i64 16}
+; CHECK: [[META7:![0-9]+]] = !{!"_ZTS1x", !2, i64 0, !2, i64 4}
+;.
diff --git a/llvm/test/Instrumentation/TypeSanitizer/byval.ll b/llvm/test/Instrumentation/TypeSanitizer/byval.ll
new file mode 100644
index 00000000000000..68ab1327b225bd
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/byval.ll
@@ -0,0 +1,88 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs
+; Test basic type sanitizer instrumentation.
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+;.
+; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata"
+; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+;.
+
+%struct.s20 = type { i32, i32, [24 x i8] }
+define void @byval_test(ptr byval(%struct.s20) align 32 %x) sanitize_type {
+; CHECK-LABEL: @byval_test(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[X:%.*]] to i64
+; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[TMP4]], i8 0, i64 256, i1 false)
+; CHECK-NEXT: ret void
+;
+entry:
+ ret void
+; NOTE: Ideally, we'd get the type from the caller's copy of the data (instead
+; of setting it all to unknown).
+}
+
+%struct = type { ptr, ptr }
+
+define ptr @test_insert_point(ptr byval(%struct) %v) {
+; CHECK-LABEL: @test_insert_point(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[V:%.*]] to i64
+; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[TMP4]], i8 0, i64 128, i1 false)
+; CHECK-NEXT: [[NAME:%.*]] = getelementptr inbounds [[STRUCT:%.*]], ptr [[V]], i64 0, i32 1
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[NAME]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[DESC_SET:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[DESC_SET]], label [[SET_TYPE:%.*]], label [[TMP5:%.*]], !prof [[PROF0:![0-9]+]]
+; CHECK: set.type:
+; CHECK-NEXT: store ptr null, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_4_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 32
+; CHECK-NEXT: [[SHADOW_BYTE_4_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_4_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -4 to ptr), ptr [[SHADOW_BYTE_4_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_5_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 40
+; CHECK-NEXT: [[SHADOW_BYTE_5_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_5_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -5 to ptr), ptr [[SHADOW_BYTE_5_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_6_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 48
+; CHECK-NEXT: [[SHADOW_BYTE_6_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_6_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -6 to ptr), ptr [[SHADOW_BYTE_6_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_7_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 56
+; CHECK-NEXT: [[SHADOW_BYTE_7_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_7_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -7 to ptr), ptr [[SHADOW_BYTE_7_PTR]], align 8
+; CHECK-NEXT: br label [[TMP5]]
+; CHECK: 5:
+; CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr [[NAME]], align 8
+; CHECK-NEXT: ret ptr [[TMP6]]
+;
+entry:
+ %name = getelementptr inbounds %struct, ptr %v, i64 0, i32 1
+ %0 = load ptr, ptr %name, align 8
+ ret ptr %0
+}
diff --git a/llvm/test/Instrumentation/TypeSanitizer/globals.ll b/llvm/test/Instrumentation/TypeSanitizer/globals.ll
new file mode 100644
index 00000000000000..05d0fd348444db
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/globals.ll
@@ -0,0 +1,66 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+ at global1 = global i32 0, align 4
+ at global2 = global i32 0, align 4
+
+; CHECK: @[[GLOBAL1:[a-zA-Z0-9_$"\\.-]+]] = global i32 0, align 4
+; CHECK: @[[GLOBAL2:[a-zA-Z0-9_$"\\.-]+]] = global i32 0, align 4
+; CHECK: @[[__TYSAN_V1_SIMPLE_20C_2B_2B_20TBAA:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat
+; CHECK: @[[__TYSAN_V1_OMNIPOTENT_20CHAR:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [16 x i8] } { i64 2, i64 1, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, i64 0, [16 x i8] c"omnipotent char\00" }, comdat
+; CHECK: @[[__TYSAN_V1_INT:[a-zA-Z0-9_$"\\.-]+]] = linkonce_odr constant { i64, i64, ptr, i64, [4 x i8] } { i64 2, i64 1, ptr @__tysan_v1_omnipotent_20char, i64 0, [4 x i8] c"int\00" }, comdat
+; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [4 x ptr] [ptr @tysan.module_ctor, ptr @__tysan_v1_Simple_20C_2b_2b_20TBAA, ptr @__tysan_v1_omnipotent_20char, ptr @__tysan_v1_int], section "llvm.metadata"
+; CHECK: @[[__TYSAN_SHADOW_MEMORY_ADDRESS:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[__TYSAN_APP_MEMORY_MASK:[a-zA-Z0-9_$"\\.-]+]] = external global i64
+; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+;.
+; CHECK-LABEL: define internal void @tysan.module_ctor(
+; CHECK-NEXT: call void @__tysan_init()
+; CHECK-NEXT: call void @__tysan_set_globals_types()
+; CHECK-NEXT: ret void
+;
+;
+; CHECK-LABEL: define internal void @__tysan_set_globals_types(
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 ptrtoint (ptr @global1 to i64), [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: store ptr @__tysan_v1_int, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: [[APP_PTR_MASKED1:%.*]] = and i64 ptrtoint (ptr @global1 to i64), [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED2:%.*]] = shl i64 [[APP_PTR_MASKED1]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT3:%.*]] = add i64 [[APP_PTR_SHIFTED2]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR4:%.*]] = inttoptr i64 [[SHADOW_PTR_INT3]] to ptr
+; CHECK-NEXT: store ptr @__tysan_v1_int, ptr [[SHADOW_PTR4]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET5:%.*]] = add i64 [[SHADOW_PTR_INT3]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR6:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET5]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR6]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET7:%.*]] = add i64 [[SHADOW_PTR_INT3]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR8:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET7]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR8]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET9:%.*]] = add i64 [[SHADOW_PTR_INT3]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR10:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET9]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR10]], align 8
+; CHECK-NEXT: ret void
+
+
+
+!llvm.tysan.globals = !{!13, !14}
+
+!0 = !{!"Simple C++ TBAA"}
+!1 = !{!"omnipotent char", !0, i64 0}
+!2 = !{!"int", !1, i64 0}
+!13 = !{ptr @global1, !2}
+!14 = !{ptr @global1, !2}
diff --git a/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll b/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll
new file mode 100644
index 00000000000000..4527aa5cf2a015
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll
@@ -0,0 +1,25 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+!llvm.tysan.globals = !{!0}
+
+!0 = distinct !{ptr undef, !1}
+!1 = !{!"any pointer", !2, i64 0}
+!2 = !{!"omnipotent char", !3, i64 0}
+!3 = !{!"Simple C/C++ TBAA"}
+;.
+; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata"
+; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+;.
+; CHECK-LABEL: @tysan.module_ctor(
+; CHECK-NEXT: call void @__tysan_init()
+; CHECK-NEXT: ret void
+;
+;.
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind }
+;.
+; CHECK: [[META0:![0-9]+]] = distinct !{ptr undef, !1}
+; CHECK: [[META1:![0-9]+]] = !{!"any pointer", !2, i64 0}
+; CHECK: [[META2:![0-9]+]] = !{!"omnipotent char", !3, i64 0}
+; CHECK: [[META3:![0-9]+]] = !{!"Simple C/C++ TBAA"}
+;.
diff --git a/llvm/test/Instrumentation/TypeSanitizer/memintrinsics.ll b/llvm/test/Instrumentation/TypeSanitizer/memintrinsics.ll
new file mode 100644
index 00000000000000..26f7c186748cb6
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/memintrinsics.ll
@@ -0,0 +1,77 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test basic type sanitizer instrumentation.
+;
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+declare void @llvm.memset.p0.i64(ptr nocapture, i8, i64, i32, i1) nounwind
+declare void @llvm.memmove.p0.p0.i64(ptr nocapture, ptr nocapture readonly, i64, i32, i1) nounwind
+declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture readonly, i64, i32, i1) nounwind
+
+define void @test_memset(ptr %a, ptr %b) nounwind uwtable sanitize_type {
+; CHECK-LABEL: @test_memset(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[TMP4]], i8 0, i64 800, i1 false)
+; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 1 [[A]], i8 0, i64 100, i1 false)
+; CHECK-NEXT: ret void
+;
+ entry:
+ tail call void @llvm.memset.p0.i64(ptr %a, i8 0, i64 100, i32 1, i1 false)
+ ret void
+}
+
+define void @test_memmove(ptr %a, ptr %b) nounwind uwtable sanitize_type {
+; CHECK-LABEL: @test_memmove(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: [[TMP5:%.*]] = ptrtoint ptr [[B:%.*]] to i64
+; CHECK-NEXT: [[TMP6:%.*]] = and i64 [[TMP5]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[TMP7:%.*]] = shl i64 [[TMP6]], 3
+; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[TMP7]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr
+; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr align 8 [[TMP4]], ptr align 8 [[TMP9]], i64 800, i1 false)
+; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr align 1 [[A]], ptr align 1 [[B]], i64 100, i1 false)
+; CHECK-NEXT: ret void
+;
+ entry:
+ tail call void @llvm.memmove.p0.p0.i64(ptr %a, ptr %b, i64 100, i32 1, i1 false)
+ ret void
+}
+
+define void @test_memcpy(ptr %a, ptr %b) nounwind uwtable sanitize_type {
+; CHECK-LABEL: @test_memcpy(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 3
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: [[TMP5:%.*]] = ptrtoint ptr [[B:%.*]] to i64
+; CHECK-NEXT: [[TMP6:%.*]] = and i64 [[TMP5]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[TMP7:%.*]] = shl i64 [[TMP6]], 3
+; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[TMP7]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr
+; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[TMP4]], ptr align 8 [[TMP9]], i64 800, i1 false)
+; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[A]], ptr align 1 [[B]], i64 100, i1 false)
+; CHECK-NEXT: ret void
+;
+ entry:
+ tail call void @llvm.memcpy.p0.p0.i64(ptr %a, ptr %b, i64 100, i32 1, i1 false)
+ ret void
+}
diff --git a/llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll b/llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll
new file mode 100644
index 00000000000000..67e408439ec165
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll
@@ -0,0 +1,39 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
+; Test basic type sanitizer instrumentation.
+;
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+;.
+; CHECK: @[[LLVM_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata"
+; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+;.
+define i32 @test_load(ptr %a) sanitize_type {
+; CHECK-LABEL: @test_load(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A:%.*]], align 4, !tbaa [[TBAA0:![0-9]+]], !nosanitize !4
+; CHECK-NEXT: ret i32 [[TMP1]]
+;
+entry:
+ %tmp1 = load i32, ptr %a, align 4, !tbaa !3, !nosanitize !{}
+ ret i32 %tmp1
+}
+
+!0 = !{!"Simple C++ TBAA"}
+!1 = !{!"omnipotent char", !0, i64 0}
+!2 = !{!"int", !1, i64 0}
+!3 = !{!2, !2, i64 0}
+!4 = !{!"_ZTS1x", !2, i64 0, !2, i64 4}
+!5 = !{!"_ZTS1v", !2, i64 8, !2, i64 12, !4, i64 16}
+!6 = !{!5, !2, i64 12}
+;.
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { sanitize_type }
+; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind }
+;.
+; CHECK: [[TBAA0]] = !{!1, !1, i64 0}
+; CHECK: [[META1:![0-9]+]] = !{!"int", !2, i64 0}
+; CHECK: [[META2:![0-9]+]] = !{!"omnipotent char", !3, i64 0}
+; CHECK: [[META3:![0-9]+]] = !{!"Simple C++ TBAA"}
+; CHECK: [[META4:![0-9]+]] = !{}
+;.
diff --git a/llvm/test/Instrumentation/TypeSanitizer/sanitize-no-tbaa.ll b/llvm/test/Instrumentation/TypeSanitizer/sanitize-no-tbaa.ll
new file mode 100644
index 00000000000000..3cb7b8365866b0
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/sanitize-no-tbaa.ll
@@ -0,0 +1,180 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test basic type sanitizer instrumentation.
+;
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @test_load_unk(ptr %a) sanitize_type {
+; CHECK-LABEL: @test_load_unk(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0:![0-9]+]]
+; CHECK: 0:
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]]
+; CHECK: 2:
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
+; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null
+; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]]
+; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr
+; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8
+; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null
+; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]]
+; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr
+; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8
+; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null
+; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]]
+; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]]
+; CHECK: 18:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 1)
+; CHECK-NEXT: br label [[TMP19]]
+; CHECK: 19:
+; CHECK-NEXT: store ptr null, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: br label [[TMP21:%.*]]
+; CHECK: 20:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 1)
+; CHECK-NEXT: br label [[TMP21]]
+; CHECK: 21:
+; CHECK-NEXT: br label [[TMP43:%.*]]
+; CHECK: 22:
+; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr
+; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8
+; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64
+; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0
+; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]]
+; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr
+; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8
+; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64
+; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0
+; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]]
+; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr
+; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8
+; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64
+; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0
+; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]]
+; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]]
+; CHECK: 41:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 1)
+; CHECK-NEXT: br label [[TMP42]]
+; CHECK: 42:
+; CHECK-NEXT: br label [[TMP43]]
+; CHECK: 43:
+; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A]], align 4
+; CHECK-NEXT: ret i32 [[TMP1]]
+;
+entry:
+ %tmp1 = load i32, ptr %a, align 4
+ ret i32 %tmp1
+}
+
+define void @test_store_unk(ptr %a) sanitize_type {
+; CHECK-LABEL: @test_store_unk(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
+; CHECK-NEXT: [[SHADOW_BASE:%.*]] = load i64, ptr @__tysan_shadow_memory_address, align 8
+; CHECK-NEXT: [[APP_PTR_INT:%.*]] = ptrtoint ptr [[A:%.*]] to i64
+; CHECK-NEXT: [[APP_PTR_MASKED:%.*]] = and i64 [[APP_PTR_INT]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[APP_PTR_SHIFTED:%.*]] = shl i64 [[APP_PTR_MASKED]], 3
+; CHECK-NEXT: [[SHADOW_PTR_INT:%.*]] = add i64 [[APP_PTR_SHIFTED]], [[SHADOW_BASE]]
+; CHECK-NEXT: [[SHADOW_PTR:%.*]] = inttoptr i64 [[SHADOW_PTR_INT]] to ptr
+; CHECK-NEXT: [[SHADOW_DESC:%.*]] = load ptr, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[BAD_DESC:%.*]] = icmp ne ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[BAD_DESC]], label [[TMP0:%.*]], label [[TMP22:%.*]], !prof [[PROF0]]
+; CHECK: 0:
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[SHADOW_DESC]], null
+; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP20:%.*]]
+; CHECK: 2:
+; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
+; CHECK-NEXT: [[TMP6:%.*]] = icmp ne ptr [[TMP5]], null
+; CHECK-NEXT: [[TMP7:%.*]] = or i1 false, [[TMP6]]
+; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP9:%.*]] = inttoptr i64 [[TMP8]] to ptr
+; CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8
+; CHECK-NEXT: [[TMP11:%.*]] = icmp ne ptr [[TMP10]], null
+; CHECK-NEXT: [[TMP12:%.*]] = or i1 [[TMP7]], [[TMP11]]
+; CHECK-NEXT: [[TMP13:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP14:%.*]] = inttoptr i64 [[TMP13]] to ptr
+; CHECK-NEXT: [[TMP15:%.*]] = load ptr, ptr [[TMP14]], align 8
+; CHECK-NEXT: [[TMP16:%.*]] = icmp ne ptr [[TMP15]], null
+; CHECK-NEXT: [[TMP17:%.*]] = or i1 [[TMP12]], [[TMP16]]
+; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19:%.*]], !prof [[PROF0]]
+; CHECK: 18:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 2)
+; CHECK-NEXT: br label [[TMP19]]
+; CHECK: 19:
+; CHECK-NEXT: store ptr null, ptr [[SHADOW_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[SHADOW_BYTE_1_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_1_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -1 to ptr), ptr [[SHADOW_BYTE_1_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_2_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[SHADOW_BYTE_2_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_2_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -2 to ptr), ptr [[SHADOW_BYTE_2_PTR]], align 8
+; CHECK-NEXT: [[SHADOW_BYTE_3_OFFSET:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[SHADOW_BYTE_3_PTR:%.*]] = inttoptr i64 [[SHADOW_BYTE_3_OFFSET]] to ptr
+; CHECK-NEXT: store ptr inttoptr (i64 -3 to ptr), ptr [[SHADOW_BYTE_3_PTR]], align 8
+; CHECK-NEXT: br label [[TMP21:%.*]]
+; CHECK: 20:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 2)
+; CHECK-NEXT: br label [[TMP21]]
+; CHECK: 21:
+; CHECK-NEXT: br label [[TMP43:%.*]]
+; CHECK: 22:
+; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[SHADOW_PTR_INT]], 8
+; CHECK-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP23]] to ptr
+; CHECK-NEXT: [[TMP25:%.*]] = load ptr, ptr [[TMP24]], align 8
+; CHECK-NEXT: [[TMP26:%.*]] = ptrtoint ptr [[TMP25]] to i64
+; CHECK-NEXT: [[TMP27:%.*]] = icmp sge i64 [[TMP26]], 0
+; CHECK-NEXT: [[TMP28:%.*]] = or i1 false, [[TMP27]]
+; CHECK-NEXT: [[TMP29:%.*]] = add i64 [[SHADOW_PTR_INT]], 16
+; CHECK-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP29]] to ptr
+; CHECK-NEXT: [[TMP31:%.*]] = load ptr, ptr [[TMP30]], align 8
+; CHECK-NEXT: [[TMP32:%.*]] = ptrtoint ptr [[TMP31]] to i64
+; CHECK-NEXT: [[TMP33:%.*]] = icmp sge i64 [[TMP32]], 0
+; CHECK-NEXT: [[TMP34:%.*]] = or i1 [[TMP28]], [[TMP33]]
+; CHECK-NEXT: [[TMP35:%.*]] = add i64 [[SHADOW_PTR_INT]], 24
+; CHECK-NEXT: [[TMP36:%.*]] = inttoptr i64 [[TMP35]] to ptr
+; CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[TMP36]], align 8
+; CHECK-NEXT: [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i64
+; CHECK-NEXT: [[TMP39:%.*]] = icmp sge i64 [[TMP38]], 0
+; CHECK-NEXT: [[TMP40:%.*]] = or i1 [[TMP34]], [[TMP39]]
+; CHECK-NEXT: br i1 [[TMP40]], label [[TMP41:%.*]], label [[TMP42:%.*]], !prof [[PROF0]]
+; CHECK: 41:
+; CHECK-NEXT: call void @__tysan_check(ptr [[A]], i32 4, ptr null, i32 2)
+; CHECK-NEXT: br label [[TMP42]]
+; CHECK: 42:
+; CHECK-NEXT: br label [[TMP43]]
+; CHECK: 43:
+; CHECK-NEXT: store i32 42, ptr [[A]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ store i32 42, ptr %a, align 4
+ ret void
+}
diff --git a/llvm/test/Instrumentation/TypeSanitizer/swifterror.ll b/llvm/test/Instrumentation/TypeSanitizer/swifterror.ll
new file mode 100644
index 00000000000000..5711fb4b839f4d
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/swifterror.ll
@@ -0,0 +1,24 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test basic type sanitizer instrumentation.
+;
+; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @test_swifterror(ptr swifterror) sanitize_type {
+; CHECK-LABEL: @test_swifterror(
+; CHECK-NEXT: [[SWIFTERROR_PTR_VALUE:%.*]] = load ptr, ptr [[TMP0:%.*]], align 8
+; CHECK-NEXT: ret void
+;
+ %swifterror_ptr_value = load ptr, ptr %0
+ ret void
+}
+
+define void @test_swifterror_2(ptr swifterror) sanitize_type {
+; CHECK-LABEL: @test_swifterror_2(
+; CHECK-NEXT: store ptr null, ptr [[TMP0:%.*]], align 8
+; CHECK-NEXT: ret void
+;
+ store ptr null, ptr %0
+ ret void
+}
>From d8bac7bf72c79719f9e43a0d862d43ed80e76883 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 18 Apr 2024 13:56:08 +0100
Subject: [PATCH 3/4] !fixup , -> ;
---
compiler-rt/cmake/config-ix.cmake | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake
index 9e24b5b28f8a90..f1531e26fb3472 100644
--- a/compiler-rt/cmake/config-ix.cmake
+++ b/compiler-rt/cmake/config-ix.cmake
@@ -728,7 +728,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;tysan,safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;asan_abi)
+set(ALL_SANITIZERS asan;dfsan;msan;hwasan;tsan;tysan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;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}")
>From e2caf4e44614c88297f13b6820f4eaddd262eb01 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Mon, 22 Apr 2024 19:14:29 +0100
Subject: [PATCH 4/4] !fixup Add tests from bugtracker.
---
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 +++++++++++++
7 files changed, 243 insertions(+)
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/compiler-rt/test/tysan/violation-pr45282.c b/compiler-rt/test/tysan/violation-pr45282.c
new file mode 100644
index 00000000000000..2cbc37b3d1832b
--- /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 00000000000000..04d68d1dd936e4
--- /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 00000000000000..d49a813933d653
--- /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 00000000000000..4187a91bde3fc4
--- /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 00000000000000..879200c8069b0b
--- /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 00000000000000..ac20f8c94e1ffd
--- /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 00000000000000..b5198c440fa443
--- /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