[clang] [llvm] [TySan] A Type Sanitizer (Clang) (PR #76260)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 17 06:00:10 PST 2024
https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/76260
>From 4c3ac21386c4032f10701f9fd9d2f37244514c99 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 22 Dec 2023 19:18:24 +0000
Subject: [PATCH 01/16] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20?=
=?UTF-8?q?initial=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Created using spr 1.3.4
---
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 41909a8fc1d590..21fd27d9838db7 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -787,6 +787,7 @@ enum AttributeKindCodes {
ATTR_KIND_CORO_ELIDE_SAFE = 98,
ATTR_KIND_NO_EXT = 99,
ATTR_KIND_NO_DIVERGENCE_SOURCE = 100,
+ ATTR_KIND_SANITIZE_TYPE = 101,
};
enum ComdatSelectionKindCodes {
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index 49f4527bde66e7..179238bc733830 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -317,6 +317,9 @@ def SanitizeAddress : EnumAttr<"sanitize_address", IntersectPreserve, [FnAttr]>;
/// ThreadSanitizer is on.
def SanitizeThread : EnumAttr<"sanitize_thread", IntersectPreserve, [FnAttr]>;
+/// TypeSanitizer is on.
+def SanitizeType : EnumAttr<"sanitize_type", [FnAttr]>;
+
/// MemorySanitizer is on.
def SanitizeMemory : EnumAttr<"sanitize_memory", IntersectPreserve, [FnAttr]>;
@@ -425,6 +428,7 @@ class CompatRuleStrAttr<string F, string Attr> : CompatRule<F> {
def : CompatRule<"isEqual<SanitizeAddressAttr>">;
def : CompatRule<"isEqual<SanitizeThreadAttr>">;
+def : CompatRule<"isEqual<SanitizeTypeAttr>">;
def : CompatRule<"isEqual<SanitizeMemoryAttr>">;
def : CompatRule<"isEqual<SanitizeHWAddressAttr>">;
def : CompatRule<"isEqual<SanitizeMemTagAttr>">;
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 fd11c3abc379e2..a499e16ff0097f 100644
--- a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
@@ -372,11 +372,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;
@@ -426,8 +442,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))
@@ -440,8 +456,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 85c6fadeda6cc3..a01ecf0d56642e 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2192,6 +2192,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_SANITIZE_NUMERICAL_STABILITY:
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 0444cb9e1bce5d..b4efd3928a2e6f 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -851,6 +851,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::SanitizeNumericalStability:
diff --git a/llvm/lib/CodeGen/ShrinkWrap.cpp b/llvm/lib/CodeGen/ShrinkWrap.cpp
index 2742437ceb5895..5029f45def2266 100644
--- a/llvm/lib/CodeGen/ShrinkWrap.cpp
+++ b/llvm/lib/CodeGen/ShrinkWrap.cpp
@@ -986,6 +986,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 260a34f2e060d6..bf9fd30d905b99 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -225,6 +225,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 2ddebb07017c2a..1ba26a30b76053 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -155,6 +155,7 @@ MODULE_PASS("strip-nonlinetable-debuginfo", StripNonLineTableDebugInfoPass())
MODULE_PASS("trigger-crash-module", TriggerCrashModulePass())
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())
@@ -478,6 +479,7 @@ FUNCTION_PASS("transform-warning", WarnMissedTransformationsPass())
FUNCTION_PASS("trigger-crash-function", TriggerCrashFunctionPass())
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 3e3c3eced4bb9c..5abc7fc8052834 100644
--- a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
+++ b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
@@ -24,6 +24,7 @@ add_llvm_component_library(LLVMInstrumentation
SanitizerBinaryMetadata.cpp
ValueProfileCollector.cpp
ThreadSanitizer.cpp
+ TypeSanitizer.cpp
HWAddressSanitizer.cpp
RealtimeSanitizer.cpp
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 6539f924c2edf4..610a77bc4c31ec 100644
--- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -935,6 +935,7 @@ Function *CodeExtractor::constructFunctionDeclaration(
case Attribute::SanitizeMemory:
case Attribute::SanitizeNumericalStability:
case Attribute::SanitizeThread:
+ case Attribute::SanitizeType:
case Attribute::SanitizeHWAddress:
case Attribute::SanitizeMemTag:
case Attribute::SanitizeRealtime:
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 e5158df6521b4b210ff8d9f510771c4d1b973e68 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 18 Apr 2024 22:52:16 +0100
Subject: [PATCH 02/16] !fixup address comments, thanks
---
.../llvm/Analysis/TypeBasedAliasAnalysis.h | 8 ++++++
llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp | 26 ++++---------------
.../Instrumentation/TypeSanitizer.cpp | 22 +++++++---------
.../Analysis/AliasSetTrackerTest.cpp | 2 +-
4 files changed, 24 insertions(+), 34 deletions(-)
diff --git a/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h b/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h
index 36dd39c033aa63..0ec84a461a3db7 100644
--- a/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h
+++ b/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h
@@ -29,7 +29,15 @@ class MemoryLocation;
/// A simple AA result that uses TBAA metadata to answer queries.
class TypeBasedAAResult : public AAResultBase {
+ /// True if type sanitizer is enabled. When TypeSanitizer is used, don't use
+ /// TBAA information for alias analysis as this might cause us to remove
+ /// memory accesses that we need to verify at runtime.
+ bool UsingTypeSanitizer;
+
public:
+ TypeBasedAAResult(bool UsingTypeSanitizer)
+ : UsingTypeSanitizer(UsingTypeSanitizer) {}
+
/// Handle invalidation events from the new pass manager.
///
/// By definition, this result is stateless and so remains valid.
diff --git a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
index a499e16ff0097f..08c7736af477e9 100644
--- a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
@@ -372,26 +372,10 @@ 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 || usingSanitizeType(LocA.Ptr) || usingSanitizeType(LocB.Ptr))
+ if (!EnableTBAA || UsingTypeSanitizer || UsingTypeSanitizer)
return AAResultBase::alias(LocA, LocB, AAQI, nullptr);
if (Aliases(LocA.AATags.TBAA, LocB.AATags.TBAA))
@@ -442,7 +426,7 @@ MemoryEffects TypeBasedAAResult::getMemoryEffects(const Function *F) {
ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call,
const MemoryLocation &Loc,
AAQueryInfo &AAQI) {
- if (!EnableTBAA || usingSanitizeType(Call))
+ if (!EnableTBAA || UsingTypeSanitizer)
return AAResultBase::getModRefInfo(Call, Loc, AAQI);
if (const MDNode *L = Loc.AATags.TBAA)
@@ -456,7 +440,7 @@ ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call,
ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call1,
const CallBase *Call2,
AAQueryInfo &AAQI) {
- if (!EnableTBAA || usingSanitizeType(Call1))
+ if (!EnableTBAA || UsingTypeSanitizer)
return AAResultBase::getModRefInfo(Call1, Call2, AAQI);
if (const MDNode *M1 = Call1->getMetadata(LLVMContext::MD_tbaa))
@@ -724,7 +708,7 @@ bool TypeBasedAAResult::Aliases(const MDNode *A, const MDNode *B) const {
AnalysisKey TypeBasedAA::Key;
TypeBasedAAResult TypeBasedAA::run(Function &F, FunctionAnalysisManager &AM) {
- return TypeBasedAAResult();
+ return TypeBasedAAResult(F.hasFnAttribute(Attribute::SanitizeType));
}
char TypeBasedAAWrapperPass::ID = 0;
@@ -740,7 +724,7 @@ TypeBasedAAWrapperPass::TypeBasedAAWrapperPass() : ImmutablePass(ID) {
}
bool TypeBasedAAWrapperPass::doInitialization(Module &M) {
- Result.reset(new TypeBasedAAResult());
+ Result.reset(new TypeBasedAAResult(false));
return false;
}
diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
index ed4aba4ad612d9..2ca9b8a8d8ce41 100644
--- a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
@@ -110,6 +110,7 @@ struct TypeSanitizer {
TypeNameMapTy &TypeNames, Module &M);
const Triple TargetTriple;
+ Regex AnonNameRegex;
Type *IntptrTy;
uint64_t PtrShift;
IntegerType *OrdTy;
@@ -122,7 +123,8 @@ struct TypeSanitizer {
} // namespace
TypeSanitizer::TypeSanitizer(Module &M)
- : TargetTriple(Triple(M.getTargetTriple())) {
+ : TargetTriple(Triple(M.getTargetTriple())),
+ AnonNameRegex("^_ZTS.*N[1-9][0-9]*_GLOBAL__N") {
const DataLayout &DL = M.getDataLayout();
IntptrTy = DL.getIntPtrType(M.getContext());
PtrShift = countr_zero(IntptrTy->getPrimitiveSizeInBits() / 8);
@@ -237,16 +239,6 @@ static std::string encodeName(StringRef Name) {
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) {
@@ -352,7 +344,13 @@ bool TypeSanitizer::generateBaseTypeDescriptor(
TDSubTys.push_back(IntptrTy);
TDSubData.push_back(ConstantInt::get(IntptrTy, Members.size()));
- bool ShouldBeComdat = !isAnonymousNamespaceName(NameNode->getString());
+ // 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.).
+ bool ShouldBeComdat = !AnonNameRegex.match(NameNode->getString());
for (auto &Member : Members) {
TDSubTys.push_back(Member.first->getType());
TDSubData.push_back(Member.first);
diff --git a/llvm/unittests/Analysis/AliasSetTrackerTest.cpp b/llvm/unittests/Analysis/AliasSetTrackerTest.cpp
index 68bd41a1e8589b..e784e6eefb79c6 100644
--- a/llvm/unittests/Analysis/AliasSetTrackerTest.cpp
+++ b/llvm/unittests/Analysis/AliasSetTrackerTest.cpp
@@ -62,7 +62,7 @@ TEST(AliasSetTracker, AliasUnknownInst) {
TargetLibraryInfoImpl TLII(Trip);
TargetLibraryInfo TLI(TLII);
AAResults AA(TLI);
- TypeBasedAAResult TBAAR;
+ TypeBasedAAResult TBAAR(false);
AA.addAAResult(TBAAR);
// Initialize the alias set tracker for the @test function.
>From 9e30a88cd14462349497b3742f81bb2d1319ded3 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 27 Jun 2024 15:08:19 +0100
Subject: [PATCH 03/16] !fiupx address comments, thanks!
---
llvm/include/llvm/IR/Attributes.td | 2 +-
.../Instrumentation/TypeSanitizer.cpp | 24 +++++++++----------
...-with-offfset.ll => access-with-offset.ll} | 0
3 files changed, 12 insertions(+), 14 deletions(-)
rename llvm/test/Instrumentation/TypeSanitizer/{access-with-offfset.ll => access-with-offset.ll} (100%)
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index 179238bc733830..61955cf883c3f1 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -318,7 +318,7 @@ def SanitizeAddress : EnumAttr<"sanitize_address", IntersectPreserve, [FnAttr]>;
def SanitizeThread : EnumAttr<"sanitize_thread", IntersectPreserve, [FnAttr]>;
/// TypeSanitizer is on.
-def SanitizeType : EnumAttr<"sanitize_type", [FnAttr]>;
+def SanitizeType : EnumAttr<"sanitize_type", IntersectPreserve, [FnAttr]>;
/// MemorySanitizer is on.
def SanitizeMemory : EnumAttr<"sanitize_memory", IntersectPreserve, [FnAttr]>;
diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
index 2ca9b8a8d8ce41..6f5f7108ada0dd 100644
--- a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
@@ -143,9 +143,9 @@ void TypeSanitizer::initializeCallbacks(Module &M) {
TysanCheck = cast<Function>(
M.getOrInsertFunction(kTysanCheckName, Attr, IRB.getVoidTy(),
IRB.getPtrTy(), // Pointer to data to be read.
- OrdTy, // Size of the data in bytes.
+ OrdTy, // Size of the data in bytes.
IRB.getPtrTy(), // Pointer to type descriptor.
- OrdTy // Flags.
+ OrdTy // Flags.
)
.getCallee());
@@ -601,7 +601,7 @@ bool TypeSanitizer::instrumentWithShadowUpdate(
Value *ShadowDataInt = ConvertToShadowDataInt(IRB, Ptr, IntptrTy, PtrShift,
ShadowBase, AppMemMask);
- Type *Int8PtrPtrTy = IRB.getPtrTy()->getPointerTo();
+ Type *Int8PtrPtrTy = PointerType::get(IRB.getPtrTy(), 0);
Value *ShadowData =
IRB.CreateIntToPtr(ShadowDataInt, Int8PtrPtrTy, "shadow.ptr");
@@ -637,8 +637,7 @@ bool TypeSanitizer::instrumentWithShadowUpdate(
Constant *Flags =
ConstantInt::get(OrdTy, (int)IsRead | (((int)IsWrite) << 1));
- Value *LoadedTD =
- IRB.CreateLoad(IRB.getPtrTy(), ShadowData, "shadow.desc");
+ Value *LoadedTD = IRB.CreateLoad(IRB.getPtrTy(), ShadowData, "shadow.desc");
if (SanitizeFunction) {
Value *BadTDCmp = IRB.CreateICmpNE(LoadedTD, TD, "bad.desc");
Instruction *BadTDTerm, *GoodTDTerm;
@@ -673,16 +672,16 @@ bool TypeSanitizer::instrumentWithShadowUpdate(
Instruction *BadUTDTerm = SplitBlockAndInsertIfThen(
NotAllUnkTD, BeforeSetType, false, UnlikelyBW);
IRB.SetInsertPoint(BadUTDTerm);
- IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()),
- Size, (Value *)TD, (Value *)Flags});
+ 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});
+ 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.
@@ -703,8 +702,8 @@ bool TypeSanitizer::instrumentWithShadowUpdate(
Instruction *BadITDTerm = SplitBlockAndInsertIfThen(
NotAllBadTD, &*IRB.GetInsertPoint(), false, UnlikelyBW);
IRB.SetInsertPoint(BadITDTerm);
- IRB.CreateCall(TysanCheck, {IRB.CreateBitCast(Ptr, IRB.getPtrTy()),
- Size, (Value *)TD, (Value *)Flags});
+ 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.
@@ -843,8 +842,7 @@ bool TypeSanitizer::instrumentMemInst(Value *V, Value *&ShadowBase,
IRB.CreateAnd(IRB.CreatePtrToInt(Src, IntptrTy), AppMemMask),
PtrShift),
ShadowBase);
- Value *SrcShadowData =
- IRB.CreateIntToPtr(SrcShadowDataInt, IRB.getPtrTy());
+ Value *SrcShadowData = IRB.CreateIntToPtr(SrcShadowDataInt, IRB.getPtrTy());
if (NeedsMemMove) {
IRB.CreateMemMove(ShadowData, Align(1u << PtrShift), SrcShadowData,
diff --git a/llvm/test/Instrumentation/TypeSanitizer/access-with-offfset.ll b/llvm/test/Instrumentation/TypeSanitizer/access-with-offset.ll
similarity index 100%
rename from llvm/test/Instrumentation/TypeSanitizer/access-with-offfset.ll
rename to llvm/test/Instrumentation/TypeSanitizer/access-with-offset.ll
>From 557abfc62ecc286af9de21a2483633fcace63e66 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 6 Dec 2024 10:39:03 +0000
Subject: [PATCH 04/16] !fixup remove Instrumentation.h include
---
llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
index 6f5f7108ada0dd..4b2820ff03f072 100644
--- a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
@@ -37,7 +37,6 @@
#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"
>From f0355888d41b0061cf2bddb3942c57b590b4ee8b Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 6 Dec 2024 13:26:07 +0000
Subject: [PATCH 05/16] !fixup address latest comments, thanks!
---
.../llvm/Analysis/TypeBasedAliasAnalysis.h | 4 +
llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp | 16 +-
.../Instrumentation/TypeSanitizer.cpp | 181 +++++++++---------
.../TypeSanitizer/invalid-metadata.ll | 17 +-
4 files changed, 116 insertions(+), 102 deletions(-)
diff --git a/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h b/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h
index 0ec84a461a3db7..e70f35174e4ca0 100644
--- a/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h
+++ b/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h
@@ -60,6 +60,10 @@ class TypeBasedAAResult : public AAResultBase {
private:
bool Aliases(const MDNode *A, const MDNode *B) const;
+
+ /// Returns true if TBAA metadata should be used, that is if TBAA is enabled
+ /// and type sanitizer is not used.
+ bool shouldUseTBAA() const;
};
/// Analysis pass providing a never-invalidated alias analysis result.
diff --git a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
index 08c7736af477e9..98da4e37a1404e 100644
--- a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
@@ -375,7 +375,7 @@ static bool isStructPathTBAA(const MDNode *MD) {
AliasResult TypeBasedAAResult::alias(const MemoryLocation &LocA,
const MemoryLocation &LocB,
AAQueryInfo &AAQI, const Instruction *) {
- if (!EnableTBAA || UsingTypeSanitizer || UsingTypeSanitizer)
+ if (!shouldUseTBAA())
return AAResultBase::alias(LocA, LocB, AAQI, nullptr);
if (Aliases(LocA.AATags.TBAA, LocB.AATags.TBAA))
@@ -388,7 +388,7 @@ AliasResult TypeBasedAAResult::alias(const MemoryLocation &LocA,
ModRefInfo TypeBasedAAResult::getModRefInfoMask(const MemoryLocation &Loc,
AAQueryInfo &AAQI,
bool IgnoreLocals) {
- if (!EnableTBAA)
+ if (!shouldUseTBAA())
return ModRefInfo::ModRef;
const MDNode *M = Loc.AATags.TBAA;
@@ -406,7 +406,7 @@ ModRefInfo TypeBasedAAResult::getModRefInfoMask(const MemoryLocation &Loc,
MemoryEffects TypeBasedAAResult::getMemoryEffects(const CallBase *Call,
AAQueryInfo &AAQI) {
- if (!EnableTBAA)
+ if (!shouldUseTBAA())
return MemoryEffects::unknown();
// If this is an "immutable" type, the access is not observable.
@@ -426,7 +426,7 @@ MemoryEffects TypeBasedAAResult::getMemoryEffects(const Function *F) {
ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call,
const MemoryLocation &Loc,
AAQueryInfo &AAQI) {
- if (!EnableTBAA || UsingTypeSanitizer)
+ if (!shouldUseTBAA())
return AAResultBase::getModRefInfo(Call, Loc, AAQI);
if (const MDNode *L = Loc.AATags.TBAA)
@@ -440,7 +440,7 @@ ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call,
ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call1,
const CallBase *Call2,
AAQueryInfo &AAQI) {
- if (!EnableTBAA || UsingTypeSanitizer)
+ if (!shouldUseTBAA())
return AAResultBase::getModRefInfo(Call1, Call2, AAQI);
if (const MDNode *M1 = Call1->getMetadata(LLVMContext::MD_tbaa))
@@ -705,6 +705,10 @@ bool TypeBasedAAResult::Aliases(const MDNode *A, const MDNode *B) const {
return matchAccessTags(A, B);
}
+bool TypeBasedAAResult::shouldUseTBAA() const {
+ return EnableTBAA && !UsingTypeSanitizer;
+}
+
AnalysisKey TypeBasedAA::Key;
TypeBasedAAResult TypeBasedAA::run(Function &F, FunctionAnalysisManager &AM) {
@@ -724,7 +728,7 @@ TypeBasedAAWrapperPass::TypeBasedAAWrapperPass() : ImmutablePass(ID) {
}
bool TypeBasedAAWrapperPass::doInitialization(Module &M) {
- Result.reset(new TypeBasedAAResult(false));
+ Result.reset(new TypeBasedAAResult(/*UsingTypeSanitizer=*/false));
return false;
}
diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
index 4b2820ff03f072..c382c67d18ab7a 100644
--- a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
@@ -22,6 +22,7 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
@@ -72,7 +73,7 @@ namespace {
struct TypeSanitizer {
TypeSanitizer(Module &M);
bool run(Function &F, const TargetLibraryInfo &TLI);
- void instrumentGlobals();
+ void instrumentGlobals(Module &M);
private:
typedef SmallDenseMap<const MDNode *, GlobalVariable *, 8>
@@ -114,9 +115,11 @@ struct TypeSanitizer {
uint64_t PtrShift;
IntegerType *OrdTy;
- // Callbacks to run-time library are computed in doInitialization.
- Function *TysanCheck;
- Function *TysanCtorFunction;
+ /// Callbacks to run-time library are computed in initializeCallbacks.
+ FunctionCallee TysanCheck;
+ FunctionCallee TysanCtorFunction;
+
+ /// Callback to set types for gloabls.
Function *TysanGlobalsSetTypeFunction;
};
} // namespace
@@ -139,29 +142,33 @@ void TypeSanitizer::initializeCallbacks(Module &M) {
AttributeList Attr;
Attr = Attr.addFnAttribute(M.getContext(), Attribute::NoUnwind);
// Initialize the callbacks.
- TysanCheck = cast<Function>(
+ TysanCheck =
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);
+void TypeSanitizer::instrumentGlobals(Module &M) {
TysanGlobalsSetTypeFunction = nullptr;
NamedMDNode *Globals = M.getNamedMetadata("llvm.tysan.globals");
if (!Globals)
return;
+ 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);
+
const DataLayout &DL = M.getDataLayout();
Value *ShadowBase = nullptr, *AppMemMask = nullptr;
TypeDescriptorsMapTy TypeDescriptors;
@@ -175,15 +182,6 @@ void TypeSanitizer::instrumentGlobals() {
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();
@@ -195,23 +193,13 @@ void TypeSanitizer::instrumentGlobals() {
}
if (TysanGlobalsSetTypeFunction) {
- IRBuilder<> IRB(TysanCtorFunction->getEntryBlock().getTerminator());
+ IRBuilder<> IRB(cast<Function>(TysanCtorFunction.getCallee())
+ ->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) {
@@ -220,7 +208,7 @@ static std::string encodeName(StringRef Name) {
Output.reserve(Output.size() + 3 * Length);
for (size_t i = 0; i < Length; ++i) {
const unsigned char c = Name[i];
- if (isalnum((int)c)) {
+ if (isalnum(c)) {
Output.push_back(c);
continue;
}
@@ -337,11 +325,13 @@ bool TypeSanitizer::generateBaseTypeDescriptor(
SmallVector<Type *> TDSubTys;
SmallVector<Constant *> TDSubData;
- TDSubTys.push_back(IntptrTy);
- TDSubData.push_back(ConstantInt::get(IntptrTy, 2));
+ auto PushTDSub = [&](Constant *C) {
+ TDSubTys.push_back(C->getType());
+ TDSubData.push_back(C);
+ };
- TDSubTys.push_back(IntptrTy);
- TDSubData.push_back(ConstantInt::get(IntptrTy, Members.size()));
+ PushTDSub(ConstantInt::get(IntptrTy, 2));
+ PushTDSub(ConstantInt::get(IntptrTy, Members.size()));
// Types that are in an anonymous namespace are local to this module.
// FIXME: This should really be marked by the frontend in the metadata
@@ -351,15 +341,11 @@ bool TypeSanitizer::generateBaseTypeDescriptor(
// anonymous namespace is a template parameter, etc.).
bool ShouldBeComdat = !AnonNameRegex.match(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));
+ PushTDSub(Member.first);
+ PushTDSub(ConstantInt::get(IntptrTy, Member.second));
}
- TDSubTys.push_back(NameData->getType());
- TDSubData.push_back(NameData);
+ PushTDSub(NameData);
StructType *TDTy = StructType::get(C, TDSubTys);
Constant *TD = ConstantStruct::get(TDTy, TDSubData);
@@ -482,59 +468,65 @@ Value *TypeSanitizer::getAppMemMask(Function &F) {
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();
+/// Collect all loads and stores, and for what TBAA nodes we need to generate
+/// type descriptors.
+void collectMemAccessInfo(
+ Function &F, const TargetLibraryInfo &TLI,
+ SmallVectorImpl<std::pair<Instruction *, MemoryLocation>> &MemoryAccesses,
+ SmallSetVector<const MDNode *, 8> &TBAAMetadata,
+ SmallVectorImpl<Value *> &MemTypeResetInsts) {
// 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;
+ for (Instruction &Inst : instructions(F)) {
+ // 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);
+ 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;
+ // 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;
+ // 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 (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)) {
+ 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);
}
}
+}
+
+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.getCallee() || &F == TysanGlobalsSetTypeFunction)
+ return false;
+ initializeCallbacks(*F.getParent());
+
+ // We need to collect all loads and stores, and know for what TBAA nodes we
+ // need to generate type descriptors.
+ SmallVector<std::pair<Instruction *, MemoryLocation>> MemoryAccesses;
+ SmallSetVector<const MDNode *, 8> TBAAMetadata;
+ SmallVector<Value *> MemTypeResetInsts;
+ collectMemAccessInfo(F, TLI, MemoryAccesses, TBAAMetadata, MemTypeResetInsts);
// byval arguments also need their types reset (they're new stack memory,
// just like allocas).
@@ -542,12 +534,11 @@ bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) {
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;
+ bool Res = false;
for (const MDNode *MD : TBAAMetadata) {
if (TypeDescriptors.count(MD))
continue;
@@ -558,6 +549,8 @@ bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) {
Res = true;
}
+ const DataLayout &DL = F.getParent()->getDataLayout();
+ bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeType);
Value *ShadowBase = nullptr, *AppMemMask = nullptr;
for (auto &MA : MemoryAccesses)
Res |= instrumentMemoryAccess(MA.first, MA.second, ShadowBase, AppMemMask,
@@ -863,6 +856,14 @@ PreservedAnalyses TypeSanitizerPass::run(Function &F,
PreservedAnalyses ModuleTypeSanitizerPass::run(Module &M,
ModuleAnalysisManager &AM) {
- insertModuleCtor(M);
+ Function *TysanCtorFunction;
+ std::tie(TysanCtorFunction, std::ignore) =
+ createSanitizerCtorAndInitFunctions(M, kTysanModuleCtorName,
+ kTysanInitName, /*InitArgTypes=*/{},
+ /*InitArgs=*/{});
+
+ TypeSanitizer TySan(M);
+ TySan.instrumentGlobals(M);
+ appendToGlobalCtors(M, TysanCtorFunction, 0);
return PreservedAnalyses::none();
}
diff --git a/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll b/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll
index 4527aa5cf2a015..43ce283c726056 100644
--- a/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll
+++ b/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll
@@ -8,18 +8,23 @@
!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: @llvm.used = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata"
+; CHECK: @llvm.global_ctors = 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: call void @__tysan_set_globals_types()
+; CHECK-NEXT: ret void
+;
+;
+; CHECK-LABEL: @__tysan_set_globals_types(
; 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"}
+; CHECK: [[META0:![0-9]+]] = distinct !{ptr undef, [[META1:![0-9]+]]}
+; CHECK: [[META1]] = !{!"any pointer", [[META2:![0-9]+]], i64 0}
+; CHECK: [[META2]] = !{!"omnipotent char", [[META3:![0-9]+]], i64 0}
+; CHECK: [[META3]] = !{!"Simple C/C++ TBAA"}
;.
>From 9e05f83123426f26007eda146b75e8a6175c4249 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 6 Dec 2024 13:27:06 +0000
Subject: [PATCH 06/16] !fixup modernize check lines.
---
.../TypeSanitizer/access-with-offset.ll | 24 ++++----
.../Instrumentation/TypeSanitizer/anon.ll | 43 +++++++++----
.../TypeSanitizer/basic-nosan.ll | 61 +++++++++++--------
.../Instrumentation/TypeSanitizer/basic.ll | 38 ++++++------
.../Instrumentation/TypeSanitizer/byval.ll | 53 ++++++++++------
.../Instrumentation/TypeSanitizer/globals.ll | 52 +++++++++-------
.../TypeSanitizer/nosanitize.ll | 16 ++---
7 files changed, 170 insertions(+), 117 deletions(-)
diff --git a/llvm/test/Instrumentation/TypeSanitizer/access-with-offset.ll b/llvm/test/Instrumentation/TypeSanitizer/access-with-offset.ll
index 297ee83527b5c1..78f3816c9aefa4 100644
--- a/llvm/test/Instrumentation/TypeSanitizer/access-with-offset.ll
+++ b/llvm/test/Instrumentation/TypeSanitizer/access-with-offset.ll
@@ -2,14 +2,14 @@
; 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
+; CHECK: @llvm.global_ctors = 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 = 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 = 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 = 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 = 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 = 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 = external global i64
+; CHECK: @__tysan_app_memory_mask = external global i64
;.
define ptr @test_load_offset(ptr %argv) {
; CHECK-LABEL: @test_load_offset(
@@ -64,8 +64,8 @@ entry:
; 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"}
+; CHECK: [[TBAA1]] = !{[[META2:![0-9]+]], [[META2]], i64 0}
+; CHECK: [[META2]] = !{!"any pointer", [[META3:![0-9]+]], i64 0}
+; CHECK: [[META3]] = !{!"omnipotent char", [[META4:![0-9]+]], i64 0}
+; CHECK: [[META4]] = !{!"Simple C/C++ TBAA"}
;.
diff --git a/llvm/test/Instrumentation/TypeSanitizer/anon.ll b/llvm/test/Instrumentation/TypeSanitizer/anon.ll
index 70f5dcefde64c1..ce4f0c1be0a4f8 100644
--- a/llvm/test/Instrumentation/TypeSanitizer/anon.ll
+++ b/llvm/test/Instrumentation/TypeSanitizer/anon.ll
@@ -5,21 +5,23 @@
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"
+;.
+; CHECK: @llvm.global_ctors = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = external global i64
+; CHECK: @__tysan_app_memory_mask = external global i64
+; CHECK: @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95 = 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 = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_____anonymous__027d9e575c5d34cb5d60d6a1d6276f95, ptr @__tysan_v1_int, i64 24 }, comdat
+; CHECK: @llvm.used = 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:
@@ -281,3 +283,18 @@ entry:
!10 = !{!9, !2, i64 24}
!11 = !{!"", !2, i64 24}
!12 = !{!11, !2, i64 24}
+;.
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { sanitize_type }
+; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind }
+;.
+; CHECK: [[PROF0]] = !{!"branch_weights", i32 1, i32 100000}
+; CHECK: [[TBAA1]] = !{[[META2:![0-9]+]], [[META3:![0-9]+]], i64 24}
+; CHECK: [[META2]] = !{!"_ZTSN12_GLOBAL__N_11zE", [[META3]], i64 24}
+; CHECK: [[META3]] = !{!"int", [[META4:![0-9]+]], i64 0}
+; CHECK: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}
+; CHECK: [[META5]] = !{!"Simple C++ TBAA"}
+; CHECK: [[TBAA6]] = !{[[META7:![0-9]+]], [[META3]], i64 24}
+; CHECK: [[META7]] = !{!"_ZTS1yIN12_GLOBAL__N_11zEE", [[META3]], i64 24}
+; CHECK: [[TBAA8]] = !{[[META9:![0-9]+]], [[META3]], i64 24}
+; CHECK: [[META9]] = !{!"", [[META3]], i64 24}
+;.
diff --git a/llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll b/llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll
index 7f25e36e6660e8..9b9522f3dba1c9 100644
--- a/llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll
+++ b/llvm/test/Instrumentation/TypeSanitizer/basic-nosan.ll
@@ -4,16 +4,33 @@
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) {
+entry:
+ %tmp1 = load i32, ptr %a, align 4, !tbaa !3
+ ret i32 %tmp1
+}
+
+define void @test_store_nsan(ptr %a) {
+entry:
+ store i32 42, ptr %a, align 4, !tbaa !3
+ ret void
+}
+
+
+!0 = !{!"Simple C++ TBAA"}
+!1 = !{!"omnipotent char", !0, i64 0}
+!2 = !{!"int", !1, i64 0}
+!3 = !{!2, !2, i64 0}
+;.
+; CHECK: @llvm.global_ctors = 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 = 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 = 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 = 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 = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1_int, ptr @__tysan_v1_int, i64 0 }, comdat
+; CHECK: @llvm.used = 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 = external global i64
+; CHECK: @__tysan_app_memory_mask = external global i64
+;.
; CHECK-LABEL: @test_load_nsan(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
@@ -42,12 +59,7 @@ define i32 @test_load_nsan(ptr %a) {
; 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
@@ -76,18 +88,17 @@ define void @test_store_nsan(ptr %a) {
; 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: attributes #[[ATTR0:[0-9]+]] = { nounwind }
+;.
; 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}
+; CHECK: [[TBAA1]] = !{[[META2:![0-9]+]], [[META2]], i64 0}
+; CHECK: [[META2]] = !{!"int", [[META3:![0-9]+]], i64 0}
+; CHECK: [[META3]] = !{!"omnipotent char", [[META4:![0-9]+]], i64 0}
+; CHECK: [[META4]] = !{!"Simple C++ TBAA"}
+;.
diff --git a/llvm/test/Instrumentation/TypeSanitizer/basic.ll b/llvm/test/Instrumentation/TypeSanitizer/basic.ll
index 132df722e83c25..41d7c999e1d367 100644
--- a/llvm/test/Instrumentation/TypeSanitizer/basic.ll
+++ b/llvm/test/Instrumentation/TypeSanitizer/basic.ll
@@ -6,18 +6,20 @@
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"
+;.
+; CHECK: @llvm.global_ctors = 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 = 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 = 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 = 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 = 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 = external global i64
+; CHECK: @__tysan_app_memory_mask = external global i64
+; CHECK: @__tysan_v1___ZTS1x = 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 = 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 = linkonce_odr constant { i64, ptr, ptr, i64 } { i64 1, ptr @__tysan_v1___ZTS1v, ptr @__tysan_v1_int, i64 12 }, comdat
+; CHECK: @llvm.used = 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:
@@ -204,11 +206,11 @@ entry:
; 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}
+; CHECK: [[TBAA1]] = !{[[META2:![0-9]+]], [[META2]], i64 0}
+; CHECK: [[META2]] = !{!"int", [[META3:![0-9]+]], i64 0}
+; CHECK: [[META3]] = !{!"omnipotent char", [[META4:![0-9]+]], i64 0}
+; CHECK: [[META4]] = !{!"Simple C++ TBAA"}
+; CHECK: [[TBAA5]] = !{[[META6:![0-9]+]], [[META2]], i64 12}
+; CHECK: [[META6]] = !{!"_ZTS1v", [[META2]], i64 8, [[META2]], i64 12, [[META7:![0-9]+]], i64 16}
+; CHECK: [[META7]] = !{!"_ZTS1x", [[META2]], i64 0, [[META2]], i64 4}
;.
diff --git a/llvm/test/Instrumentation/TypeSanitizer/byval.ll b/llvm/test/Instrumentation/TypeSanitizer/byval.ll
index 68ab1327b225bd..23ed1b00173bfc 100644
--- a/llvm/test/Instrumentation/TypeSanitizer/byval.ll
+++ b/llvm/test/Instrumentation/TypeSanitizer/byval.ll
@@ -4,15 +4,29 @@
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 {
+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) {
+entry:
+ %name = getelementptr inbounds %struct, ptr %v, i64 0, i32 1
+ %0 = load ptr, ptr %name, align 8
+ ret ptr %0
+}
+;.
+; CHECK: @llvm.used = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata"
+; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+; CHECK: @__tysan_shadow_memory_address = external global i64
+; CHECK: @__tysan_app_memory_mask = external global i64
+;.
; CHECK-LABEL: @byval_test(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[APP_MEM_MASK:%.*]] = load i64, ptr @__tysan_app_memory_mask, align 8
@@ -25,15 +39,7 @@ define void @byval_test(ptr byval(%struct.s20) align 32 %x) sanitize_type {
; 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
@@ -81,8 +87,15 @@ define ptr @test_insert_point(ptr byval(%struct) %v) {
; 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
-}
+;
+; CHECK-LABEL: @tysan.module_ctor(
+; CHECK-NEXT: call void @__tysan_init()
+; CHECK-NEXT: ret void
+;
+;.
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { sanitize_type }
+; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind }
+; CHECK: attributes #[[ATTR2:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: write) }
+;.
+; CHECK: [[PROF0]] = !{!"branch_weights", i32 1, i32 100000}
+;.
diff --git a/llvm/test/Instrumentation/TypeSanitizer/globals.ll b/llvm/test/Instrumentation/TypeSanitizer/globals.ll
index 05d0fd348444db..f4f933f0170909 100644
--- a/llvm/test/Instrumentation/TypeSanitizer/globals.ll
+++ b/llvm/test/Instrumentation/TypeSanitizer/globals.ll
@@ -6,23 +6,34 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@global1 = global i32 0, align 4
@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 }]
+
+
+
+!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}
;.
-; CHECK-LABEL: define internal void @tysan.module_ctor(
+; CHECK: @global1 = global i32 0, align 4
+; CHECK: @global2 = global i32 0, align 4
+; CHECK: @__tysan_v1_Simple_20C_2b_2b_20TBAA = 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 = 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 = 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 = 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 = external global i64
+; CHECK: @__tysan_app_memory_mask = external global i64
+; CHECK: @llvm.global_ctors = 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: call void @__tysan_set_globals_types()
; CHECK-NEXT: ret void
;
;
-; CHECK-LABEL: define internal void @__tysan_set_globals_types(
+; CHECK-LABEL: @__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]]
@@ -54,13 +65,12 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
; 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}
+;
+;.
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind }
+;.
+; CHECK: [[META0:![0-9]+]] = !{ptr @global1, [[META1:![0-9]+]]}
+; CHECK: [[META1]] = !{!"int", [[META2:![0-9]+]], i64 0}
+; CHECK: [[META2]] = !{!"omnipotent char", [[META3:![0-9]+]], i64 0}
+; CHECK: [[META3]] = !{!"Simple C++ TBAA"}
+;.
diff --git a/llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll b/llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll
index 67e408439ec165..7b07a42379b3a1 100644
--- a/llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll
+++ b/llvm/test/Instrumentation/TypeSanitizer/nosanitize.ll
@@ -6,13 +6,13 @@
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: @llvm.used = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata"
+; CHECK: @llvm.global_ctors = 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: [[TMP1:%.*]] = load i32, ptr [[A:%.*]], align 4, !tbaa [[TBAA0:![0-9]+]], !nosanitize [[META4:![0-9]+]]
; CHECK-NEXT: ret i32 [[TMP1]]
;
entry:
@@ -31,9 +31,9 @@ entry:
; 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]+]] = !{}
+; CHECK: [[TBAA0]] = !{[[META1:![0-9]+]], [[META1]], i64 0}
+; CHECK: [[META1]] = !{!"int", [[META2:![0-9]+]], i64 0}
+; CHECK: [[META2]] = !{!"omnipotent char", [[META3:![0-9]+]], i64 0}
+; CHECK: [[META3]] = !{!"Simple C++ TBAA"}
+; CHECK: [[META4]] = !{}
;.
>From 1dd1d14ff9343ec15909c1e52ceddc5f860bca51 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 6 Dec 2024 13:37:52 +0000
Subject: [PATCH 07/16] !fixup pass ShadowBase/AppMemMask by value.
---
.../Instrumentation/TypeSanitizer.cpp | 25 ++++++++-----------
.../Instrumentation/TypeSanitizer/globals.ll | 13 +++++-----
.../TypeSanitizer/invalid-metadata.ll | 13 +++++++---
3 files changed, 27 insertions(+), 24 deletions(-)
diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
index c382c67d18ab7a..a02eedad7f61cc 100644
--- a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
@@ -87,13 +87,13 @@ struct TypeSanitizer {
bool instrumentWithShadowUpdate(IRBuilder<> &IRB, const MDNode *TBAAMD,
Value *Ptr, uint64_t AccessSize, bool IsRead,
- bool IsWrite, Value *&ShadowBase,
- Value *&AppMemMask, bool ForceSetType,
+ 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,
+ Value *ShadowBase, Value *AppMemMask,
bool SanitizeFunction,
TypeDescriptorsMapTy &TypeDescriptors,
const DataLayout &DL);
@@ -170,7 +170,8 @@ void TypeSanitizer::instrumentGlobals(Module &M) {
ReturnInst::Create(M.getContext(), BB);
const DataLayout &DL = M.getDataLayout();
- Value *ShadowBase = nullptr, *AppMemMask = nullptr;
+ Value *ShadowBase = getShadowBase(*TysanGlobalsSetTypeFunction);
+ Value *AppMemMask = getAppMemMask(*TysanGlobalsSetTypeFunction);
TypeDescriptorsMapTy TypeDescriptors;
TypeNameMapTy TypeNames;
@@ -551,7 +552,8 @@ bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) {
const DataLayout &DL = F.getParent()->getDataLayout();
bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeType);
- Value *ShadowBase = nullptr, *AppMemMask = nullptr;
+ Value *ShadowBase = MemoryAccesses.empty() ? nullptr : getShadowBase(F);
+ Value *AppMemMask = MemoryAccesses.empty() ? nullptr : getAppMemMask(F);
for (auto &MA : MemoryAccesses)
Res |= instrumentMemoryAccess(MA.first, MA.second, ShadowBase, AppMemMask,
SanitizeFunction, TypeDescriptors, DL);
@@ -575,14 +577,9 @@ static Value *ConvertToShadowDataInt(IRBuilder<> &IRB, Value *Ptr,
bool TypeSanitizer::instrumentWithShadowUpdate(
IRBuilder<> &IRB, const MDNode *TBAAMD, Value *Ptr, uint64_t AccessSize,
- bool IsRead, bool IsWrite, Value *&ShadowBase, Value *&AppMemMask,
+ 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];
@@ -716,9 +713,9 @@ bool TypeSanitizer::instrumentWithShadowUpdate(
}
bool TypeSanitizer::instrumentMemoryAccess(
- Instruction *I, MemoryLocation &MLoc, Value *&ShadowBase,
- Value *&AppMemMask, bool SanitizeFunction,
- TypeDescriptorsMapTy &TypeDescriptors, const DataLayout &DL) {
+ Instruction *I, MemoryLocation &MLoc, Value *ShadowBase, Value *AppMemMask,
+ bool SanitizeFunction, TypeDescriptorsMapTy &TypeDescriptors,
+ const DataLayout &DL) {
IRBuilder<> IRB(I);
assert(MLoc.Size.isPrecise());
if (instrumentWithShadowUpdate(
diff --git a/llvm/test/Instrumentation/TypeSanitizer/globals.ll b/llvm/test/Instrumentation/TypeSanitizer/globals.ll
index f4f933f0170909..1f57c2a3816d9f 100644
--- a/llvm/test/Instrumentation/TypeSanitizer/globals.ll
+++ b/llvm/test/Instrumentation/TypeSanitizer/globals.ll
@@ -1,4 +1,4 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --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"
@@ -19,21 +19,22 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
;.
; CHECK: @global1 = global i32 0, align 4
; CHECK: @global2 = global i32 0, align 4
+; CHECK: @__tysan_shadow_memory_address = external global i64
+; CHECK: @__tysan_app_memory_mask = external global i64
; CHECK: @__tysan_v1_Simple_20C_2b_2b_20TBAA = 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 = 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 = 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 = 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 = external global i64
-; CHECK: @__tysan_app_memory_mask = external global i64
; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
;.
-; CHECK-LABEL: @tysan.module_ctor(
+; CHECK-LABEL: define {{[^@]+}}@tysan.module_ctor
+; CHECK-SAME: () #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: call void @__tysan_init()
; CHECK-NEXT: call void @__tysan_set_globals_types()
; CHECK-NEXT: ret void
;
;
-; CHECK-LABEL: @__tysan_set_globals_types(
+; CHECK-LABEL: define {{[^@]+}}@__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]]
@@ -67,7 +68,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
; CHECK-NEXT: ret void
;
;.
-; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind }
+; CHECK: attributes #[[ATTR0]] = { nounwind }
;.
; CHECK: [[META0:![0-9]+]] = !{ptr @global1, [[META1:![0-9]+]]}
; CHECK: [[META1]] = !{!"int", [[META2:![0-9]+]], i64 0}
diff --git a/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll b/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll
index 43ce283c726056..da7401e9f8871a 100644
--- a/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll
+++ b/llvm/test/Instrumentation/TypeSanitizer/invalid-metadata.ll
@@ -1,4 +1,4 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-globals --include-generated-funcs
; RUN: opt -passes='tysan-module,tysan' -S %s | FileCheck %s
!llvm.tysan.globals = !{!0}
@@ -9,19 +9,24 @@
!3 = !{!"Simple C/C++ TBAA"}
;.
; CHECK: @llvm.used = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata"
+; CHECK: @__tysan_shadow_memory_address = external global i64
+; CHECK: @__tysan_app_memory_mask = external global i64
; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
;.
-; CHECK-LABEL: @tysan.module_ctor(
+; CHECK-LABEL: define {{[^@]+}}@tysan.module_ctor
+; CHECK-SAME: () #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: call void @__tysan_init()
; CHECK-NEXT: call void @__tysan_set_globals_types()
; CHECK-NEXT: ret void
;
;
-; CHECK-LABEL: @__tysan_set_globals_types(
+; CHECK-LABEL: define {{[^@]+}}@__tysan_set_globals_types() {
+; 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: ret void
;
;.
-; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind }
+; CHECK: attributes #[[ATTR0]] = { nounwind }
;.
; CHECK: [[META0:![0-9]+]] = distinct !{ptr undef, [[META1:![0-9]+]]}
; CHECK: [[META1]] = !{!"any pointer", [[META2:![0-9]+]], i64 0}
>From 4c19928ef39f9e63d7f1d7cd2f422c7f0f2574ae Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 10 Dec 2024 10:24:58 +0000
Subject: [PATCH 08/16] !fixup address first set of comments, thanks!
---
.../Instrumentation/TypeSanitizer.cpp | 59 +++++++------------
.../TypeSanitizer/alloca-only.ll | 49 +++++++++++++++
.../Instrumentation/TypeSanitizer/basic.ll | 2 -
3 files changed, 71 insertions(+), 39 deletions(-)
create mode 100644 llvm/test/Instrumentation/TypeSanitizer/alloca-only.ll
diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
index a02eedad7f61cc..6cbb9b8b9ed335 100644
--- a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
@@ -64,11 +64,9 @@ static cl::opt<bool>
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
+/// TypeSanitizer: instrument the code in module to find type-based aliasing
/// violations.
struct TypeSanitizer {
TypeSanitizer(Module &M);
@@ -92,11 +90,9 @@ struct TypeSanitizer {
bool SanitizeFunction,
TypeDescriptorsMapTy &TypeDescriptors,
const DataLayout &DL);
- bool instrumentMemoryAccess(Instruction *I, MemoryLocation &MLoc,
- Value *ShadowBase, Value *AppMemMask,
- bool SanitizeFunction,
- TypeDescriptorsMapTy &TypeDescriptors,
- const DataLayout &DL);
+
+ /// Memory-related intrinsics/instructions reset the type of the destination
+ /// memory (including allocas and byval arguments).
bool instrumentMemInst(Value *I, Value *&ShadowBase, Value *&AppMemMask,
const DataLayout &DL);
@@ -150,9 +146,8 @@ void TypeSanitizer::initializeCallbacks(Module &M) {
OrdTy // Flags.
);
- TysanCtorFunction = cast<Function>(
- M.getOrInsertFunction(kTysanModuleCtorName, Attr, IRB.getVoidTy())
- .getCallee());
+ TysanCtorFunction =
+ M.getOrInsertFunction(kTysanModuleCtorName, Attr, IRB.getVoidTy());
}
void TypeSanitizer::instrumentGlobals(Module &M) {
@@ -535,7 +530,6 @@ bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) {
if (A.hasByValAttr())
MemTypeResetInsts.push_back(&A);
-
Module &M = *F.getParent();
TypeDescriptorsMapTy TypeDescriptors;
TypeNameMapTy TypeNames;
@@ -552,11 +546,22 @@ bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) {
const DataLayout &DL = F.getParent()->getDataLayout();
bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeType);
- Value *ShadowBase = MemoryAccesses.empty() ? nullptr : getShadowBase(F);
- Value *AppMemMask = MemoryAccesses.empty() ? nullptr : getAppMemMask(F);
- for (auto &MA : MemoryAccesses)
- Res |= instrumentMemoryAccess(MA.first, MA.second, ShadowBase, AppMemMask,
- SanitizeFunction, TypeDescriptors, DL);
+ bool NeedsInstrumentation =
+ MemTypeResetInsts.empty() && MemoryAccesses.empty();
+ Value *ShadowBase = NeedsInstrumentation ? nullptr : getShadowBase(F);
+ Value *AppMemMask = NeedsInstrumentation ? nullptr : getAppMemMask(F);
+ for (const auto &[I, MLoc] : MemoryAccesses) {
+ 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;
+ Res = true;
+ }
+ }
for (auto Inst : MemTypeResetInsts)
Res |= instrumentMemInst(Inst, ShadowBase, AppMemMask, DL);
@@ -712,26 +717,6 @@ bool TypeSanitizer::instrumentWithShadowUpdate(
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) {
diff --git a/llvm/test/Instrumentation/TypeSanitizer/alloca-only.ll b/llvm/test/Instrumentation/TypeSanitizer/alloca-only.ll
new file mode 100644
index 00000000000000..1aa47cacc1275a
--- /dev/null
+++ b/llvm/test/Instrumentation/TypeSanitizer/alloca-only.ll
@@ -0,0 +1,49 @@
+; 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 = appending global [1 x ptr] [ptr @tysan.module_ctor], section "llvm.metadata"
+; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tysan.module_ctor, ptr null }]
+; CHECK: @__tysan_shadow_memory_address = external global i64
+; CHECK: @__tysan_app_memory_mask = external global i64
+;.
+define void @test_alloca_only() sanitize_type {
+; CHECK-LABEL: @test_alloca_only(
+; 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: [[TMP1:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[TMP1]] to i64
+; CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP0]], [[APP_MEM_MASK]]
+; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP5]], 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 32, i1 false)
+; CHECK-NEXT: call void @foo(ptr [[TMP1]])
+; CHECK-NEXT: ret void
+;
+entry:
+ %a = alloca i32
+ call void @foo(ptr %a)
+ ret void
+}
+
+declare void @foo(ptr)
+
+
+!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: attributes #[[ATTR2:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: write) }
+;.
diff --git a/llvm/test/Instrumentation/TypeSanitizer/basic.ll b/llvm/test/Instrumentation/TypeSanitizer/basic.ll
index 41d7c999e1d367..8873a40798b18a 100644
--- a/llvm/test/Instrumentation/TypeSanitizer/basic.ll
+++ b/llvm/test/Instrumentation/TypeSanitizer/basic.ll
@@ -5,8 +5,6 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
-
-
;.
; CHECK: @llvm.global_ctors = 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 = linkonce_odr constant { i64, i64, [16 x i8] } { i64 2, i64 0, [16 x i8] c"Simple C++ TBAA\00" }, comdat
>From 694cb2cbe5216294723f416c2fc404b879ae4e74 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 10 Dec 2024 11:42:29 +0000
Subject: [PATCH 09/16] !Fixup address remaining comments, thanks!
---
llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp | 6 +-
.../Instrumentation/TypeSanitizer.cpp | 263 +++++++++++-------
2 files changed, 158 insertions(+), 111 deletions(-)
diff --git a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
index 98da4e37a1404e..3f44f746eb173a 100644
--- a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
@@ -376,7 +376,7 @@ AliasResult TypeBasedAAResult::alias(const MemoryLocation &LocA,
const MemoryLocation &LocB,
AAQueryInfo &AAQI, const Instruction *) {
if (!shouldUseTBAA())
- return AAResultBase::alias(LocA, LocB, AAQI, nullptr);
+ return AliasResult::MayAlias;
if (Aliases(LocA.AATags.TBAA, LocB.AATags.TBAA))
return AliasResult::MayAlias;
@@ -427,7 +427,7 @@ ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call,
const MemoryLocation &Loc,
AAQueryInfo &AAQI) {
if (!shouldUseTBAA())
- return AAResultBase::getModRefInfo(Call, Loc, AAQI);
+ return ModRefInfo::ModRef;
if (const MDNode *L = Loc.AATags.TBAA)
if (const MDNode *M = Call->getMetadata(LLVMContext::MD_tbaa))
@@ -441,7 +441,7 @@ ModRefInfo TypeBasedAAResult::getModRefInfo(const CallBase *Call1,
const CallBase *Call2,
AAQueryInfo &AAQI) {
if (!shouldUseTBAA())
- return AAResultBase::getModRefInfo(Call1, Call2, AAQI);
+ return ModRefInfo::ModRef;
if (const MDNode *M1 = Call1->getMetadata(LLVMContext::MD_tbaa))
if (const MDNode *M2 = Call2->getMetadata(LLVMContext::MD_tbaa))
diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
index 6cbb9b8b9ed335..a2310983c63e3d 100644
--- a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
@@ -80,8 +80,8 @@ struct TypeSanitizer {
void initializeCallbacks(Module &M);
- Value *getShadowBase(Function &F);
- Value *getAppMemMask(Function &F);
+ Instruction *getShadowBase(Function &F);
+ Instruction *getAppMemMask(Function &F);
bool instrumentWithShadowUpdate(IRBuilder<> &IRB, const MDNode *TBAAMD,
Value *Ptr, uint64_t AccessSize, bool IsRead,
@@ -93,8 +93,8 @@ struct TypeSanitizer {
/// Memory-related intrinsics/instructions reset the type of the destination
/// memory (including allocas and byval arguments).
- bool instrumentMemInst(Value *I, Value *&ShadowBase, Value *&AppMemMask,
- const DataLayout &DL);
+ bool instrumentMemInst(Value *I, Instruction *ShadowBase,
+ Instruction *AppMemMask, const DataLayout &DL);
std::string getAnonymousStructIdentifier(const MDNode *MD,
TypeNameMapTy &TypeNames);
@@ -450,14 +450,14 @@ bool TypeSanitizer::generateTypeDescriptor(
return true;
}
-Value *TypeSanitizer::getShadowBase(Function &F) {
+Instruction *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) {
+Instruction *TypeSanitizer::getAppMemMask(Function &F) {
IRBuilder<> IRB(&F.front().front());
Value *GlobalAppMemMask =
F.getParent()->getOrInsertGlobal(kTysanAppMemMask, IntptrTy);
@@ -548,8 +548,8 @@ bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) {
bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeType);
bool NeedsInstrumentation =
MemTypeResetInsts.empty() && MemoryAccesses.empty();
- Value *ShadowBase = NeedsInstrumentation ? nullptr : getShadowBase(F);
- Value *AppMemMask = NeedsInstrumentation ? nullptr : getAppMemMask(F);
+ Instruction *ShadowBase = NeedsInstrumentation ? nullptr : getShadowBase(F);
+ Instruction *AppMemMask = NeedsInstrumentation ? nullptr : getAppMemMask(F);
for (const auto &[I, MLoc] : MemoryAccesses) {
IRBuilder<> IRB(I);
assert(MLoc.Size.isPrecise());
@@ -569,7 +569,7 @@ bool TypeSanitizer::run(Function &F, const TargetLibraryInfo &TLI) {
return Res;
}
-static Value *ConvertToShadowDataInt(IRBuilder<> &IRB, Value *Ptr,
+static Value *convertToShadowDataInt(IRBuilder<> &IRB, Value *Ptr,
Type *IntptrTy, uint64_t PtrShift,
Value *ShadowBase, Value *AppMemMask) {
return IRB.CreateAdd(
@@ -593,7 +593,7 @@ bool TypeSanitizer::instrumentWithShadowUpdate(
Value *TD = IRB.CreateBitCast(TDGV, IRB.getPtrTy());
- Value *ShadowDataInt = ConvertToShadowDataInt(IRB, Ptr, IntptrTy, PtrShift,
+ Value *ShadowDataInt = convertToShadowDataInt(IRB, Ptr, IntptrTy, PtrShift,
ShadowBase, AppMemMask);
Type *Int8PtrPtrTy = PointerType::get(IRB.getPtrTy(), 0);
Value *ShadowData =
@@ -620,105 +620,155 @@ bool TypeSanitizer::instrumentWithShadowUpdate(
}
};
- 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);
+ if (ForceSetType || (ClWritesAlwaysSetType && 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;
+ }
- Constant *Flags =
- ConstantInt::get(OrdTy, (int)IsRead | (((int)IsWrite) << 1));
+ assert((!ClWritesAlwaysSetType || IsRead) &&
+ "should have handled case above");
+ LLVMContext &C = IRB.getContext();
+ MDNode *UnlikelyBW = MDBuilder(C).createBranchWeights(1, 100000);
+ if (!SanitizeFunction) {
+ // If we're not sanitizing this function, then we only care whether we
+ // need to *set* the type.
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.
+ Value *NullTDCmp = IRB.CreateIsNull(LoadedTD, "desc.set");
+ Instruction *NullTDTerm = SplitBlockAndInsertIfThen(
+ NullTDCmp, &*IRB.GetInsertPoint(), false, UnlikelyBW);
+ IRB.SetInsertPoint(NullTDTerm);
+ NullTDTerm->getParent()->setName("set.type");
SetType();
+ return true;
+ }
+ // 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).
+ //
+ // The checks generated below have the following strucutre.
+ //
+ // ; First we load the descriptor for the load from shadow memory and
+ // ; compare it against the type descriptor for the current access type.
+ // %shadow.desc = load ptr %shadow.data
+ // %bad.desc = icmp ne %shadow.desc, %td
+ // br %bad.desc, %bad.bb, %good.bb
+ //
+ // bad.bb:
+ // %shadow.desc.null = icmp eq %shadow.desc, null
+ // br %shadow.desc.null, %null.td.bb, %good.td.bb
+ //
+ // null.td.bb:
+ // ; The typ is unknown, set it if all bytes in the value are also unknown.
+ // ; To check, we load the shadow data for all bytes of the access. For the
+ // ; pseudo code below, assume an access of size 1.
+ // %shadow.data.int = add %shadow.data.int, 0
+ // %l = load (inttoptr %shadow.data.int)
+ // %is.not.null = icmp ne %l, null
+ // %not.all.unknown = %is.not.null
+ // br %no.all.unknown, before.set.type.bb
+ //
+ // before.set.type.bb:
+ // ; Call runtime to check mismatch.
+ // call void @__tysan_check()
+ // br %set.type.bb
+ //
+ // set.type.bb:
+ // ; Now fill the remainder of the shadow memory corresponding to the
+ // ; remainder of the the bytes of the type with a bad type descriptor.
+ // store %TD, %shadow.data
+ // br %continue.bb
+ //
+ // good.td.bb::
+ // ; We have a non-trivial mismatch. Call the runtime.
+ // call void @__tysan_check()
+ // br %continue.bb
+ //
+ // good.bb:
+ // ; 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.
+ // %shadow.data.int = add %shadow.data.int, 0
+ // %l = load (inttoptr %shadow.data.int)
+ // %not.all.interior = icmp sge %l, 0
+ // br %not.all.interior, label %check.rt.bb, label %continue.bb
+ //
+ // check.rt.bb:
+ // call void @__tysan_check()
+ // br %continue.bb
+
+ Constant *Flags = ConstantInt::get(OrdTy, int(IsRead) | (int(IsWrite) << 1));
+
+ Value *LoadedTD = IRB.CreateLoad(IRB.getPtrTy(), ShadowData, "shadow.desc");
+ 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});
return true;
}
-bool TypeSanitizer::instrumentMemInst(Value *V, Value *&ShadowBase,
- Value *&AppMemMask,
+bool TypeSanitizer::instrumentMemInst(Value *V, Instruction *ShadowBase,
+ Instruction *AppMemMask,
const DataLayout &DL) {
BasicBlock::iterator IP;
BasicBlock *BB;
@@ -734,14 +784,11 @@ bool TypeSanitizer::instrumentMemInst(Value *V, Value *&ShadowBase,
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();
- }
+ // Find the next insert point after both ShadowBase and AppMemMask.
+ if (IP->comesBefore(ShadowBase))
+ IP = ShadowBase->getNextNode()->getIterator();
+ if (IP->comesBefore(AppMemMask))
+ IP = AppMemMask->getNextNode()->getIterator();
}
Value *Dest, *Size, *Src = nullptr;
>From be6f7598cc936c5d7fff722fdee50bd254a64396 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 18 Apr 2024 23:01:03 +0100
Subject: [PATCH 10/16] [TySan] A Type Sanitizer (Clang)
---
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 | 40 +++++++++++++++++-----
clang/lib/CodeGen/SanitizerMetadata.h | 13 +++----
clang/lib/Driver/SanitizerArgs.cpp | 13 ++++---
clang/lib/Driver/ToolChains/CommonArgs.cpp | 6 +++-
clang/lib/Driver/ToolChains/Darwin.cpp | 6 ++++
clang/lib/Driver/ToolChains/Linux.cpp | 2 ++
clang/test/Driver/sanitizer-ld.c | 23 +++++++++++++
16 files changed, 114 insertions(+), 27 deletions(-)
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 15c59c6bcdf29c..c82b6d9b5f6c10 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -102,6 +102,7 @@ FEATURE(numerical_stability_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Nume
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 9223f62b3639a7..f234488eaa80cf 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 0c6f3869549ef7..4f08ea2b260179 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -87,6 +87,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 8cf44592a17475..e719926ac47f4f 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -77,6 +77,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"
@@ -735,6 +736,11 @@ static void addSanitizers(const Triple &TargetTriple,
MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
}
+ if (LangOpts.Sanitize.has(SanitizerKind::Type)) {
+ MPM.addPass(ModuleTypeSanitizerPass());
+ MPM.addPass(createModuleToFunctionPassAdaptor(TypeSanitizerPass()));
+ }
+
if (LangOpts.Sanitize.has(SanitizerKind::NumericalStability))
MPM.addPass(NumericalStabilitySanitizerPass());
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 47b21bc9f63f04..bb9d120c37ca86 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -458,7 +458,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 2c3054605ee754..96517511b21114 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -479,6 +479,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 2bc10cdd2d3441..af58fa64f86585 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -837,6 +837,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.has(SanitizerKind::NumericalStability))
Fn->addFnAttr(llvm::Attribute::SanitizeNumericalStability);
if (SanOpts.hasOneOf(SanitizerKind::Memory | SanitizerKind::KernelMemory))
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index d3d5c0743a520b..a2f6a8a481113d 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -397,8 +397,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, getTypes(), TheModule, CodeGenOpts,
getLangOpts()));
@@ -5162,7 +5162,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty,
}
if (D)
- SanitizerMD->reportGlobal(GV, *D);
+ SanitizerMD->reportGlobalToASan(GV, *D);
LangAS ExpectedAS =
D ? D->getType().getAddressSpace()
@@ -5728,7 +5728,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())
@@ -6618,7 +6619,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 6eed8e1d2b671a..75e66bae79afdc 100644
--- a/clang/lib/CodeGen/CodeGenTBAA.cpp
+++ b/clang/lib/CodeGen/CodeGenTBAA.cpp
@@ -314,8 +314,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 c1a6b223480a19..c551a2529805c1 100644
--- a/clang/lib/CodeGen/SanitizerMetadata.cpp
+++ b/clang/lib/CodeGen/SanitizerMetadata.cpp
@@ -31,11 +31,11 @@ static 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;
@@ -72,8 +72,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;
@@ -95,6 +95,30 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &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 1abfe8fd92807e..e826cd627693f4 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -37,15 +37,15 @@ static const SanitizerMask NotAllowedWithMinimalRuntime = SanitizerKind::Vptr;
static const SanitizerMask NotAllowedWithExecuteOnly =
SanitizerKind::Function | SanitizerKind::KCFI;
static const SanitizerMask NeedsUnwindTables =
- SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread |
+ SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Type | SanitizerKind::Thread |
SanitizerKind::Memory | SanitizerKind::DataFlow |
SanitizerKind::NumericalStability;
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 |
@@ -182,6 +182,7 @@ static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds,
{"msan_ignorelist.txt", SanitizerKind::Memory},
{"nsan_ignorelist.txt", SanitizerKind::NumericalStability},
{"tsan_ignorelist.txt", SanitizerKind::Thread},
+ {"tysan_blacklist.txt", SanitizerKind::Type},
{"dfsan_abilist.txt", SanitizerKind::DataFlow},
{"cfi_ignorelist.txt", SanitizerKind::CFI},
{"ubsan_ignorelist.txt",
@@ -526,6 +527,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 03dbdc27975b42..cb545b6def92c7 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -1445,8 +1445,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");
@@ -1519,6 +1521,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 87380869f6fdab..7bd3179deb227a 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -1596,6 +1596,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);
@@ -3599,6 +3601,10 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
Res |= SanitizerKind::Thread;
}
+ if ((IsX86_64 || IsAArch64) && isTargetMacOSBased()) {
+ Res |= SanitizerKind::Type;
+ }
+
if (IsX86_64)
Res |= SanitizerKind::NumericalStability;
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index 46962e88d45502..c91b55b5a2948c 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -837,6 +837,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 || IsPowerPC64)
Res |= SanitizerKind::KernelMemory;
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch ||
diff --git a/clang/test/Driver/sanitizer-ld.c b/clang/test/Driver/sanitizer-ld.c
index 877a01c3de3047..2083a3c4c67a44 100644
--- a/clang/test/Driver/sanitizer-ld.c
+++ b/clang/test/Driver/sanitizer-ld.c
@@ -274,6 +274,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 \
>From 9adf5bed94b43a017a31e47219db9368715a88c2 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 18 Apr 2024 23:03:05 +0100
Subject: [PATCH 11/16] !fixup: add test
---
clang/lib/CodeGen/SanitizerMetadata.cpp | 2 +-
clang/test/CodeGen/sanitize-type-attr.cpp | 74 +++++++++++++++++++++++
2 files changed, 75 insertions(+), 1 deletion(-)
create mode 100644 clang/test/CodeGen/sanitize-type-attr.cpp
diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp
index c551a2529805c1..903ee65dd3eaa4 100644
--- a/clang/lib/CodeGen/SanitizerMetadata.cpp
+++ b/clang/lib/CodeGen/SanitizerMetadata.cpp
@@ -91,7 +91,7 @@ void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
return NoSanitizeMask;
};
- reportGlobal(GV, D.getLocation(), QualName, D.getType(), getNoSanitizeMask(D),
+ reportGlobalToASan(GV, D.getLocation(), QualName, D.getType(), getNoSanitizeMask(D),
IsDynInit);
}
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
>From 349c32d23e02161b4b23f9d9bdccec727c035574 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 22 Nov 2024 19:23:16 +0000
Subject: [PATCH 12/16] !fixup formatting and add release note.
---
clang/docs/ReleaseNotes.rst | 4 ++++
clang/lib/CodeGen/SanitizerMetadata.cpp | 4 ++--
clang/lib/Driver/SanitizerArgs.cpp | 4 ++--
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a541d399d1e749..b7bf7b2955dc02 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1155,6 +1155,10 @@ Sanitizers
<https://clang.llvm.org/docs/SanitizerSpecialCaseList.html>`_. See that link
for examples.
+- Introduced an experimental Type Sanitizer, activated by using the
+ -fsanitize=type flag. This sanitizer detects violations of C/C++ type-based
+ aliasing rules.
+
Python Binding Changes
----------------------
- Fixed an issue that led to crashes when calling ``Type.get_exception_specification_kind``.
diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp
index 903ee65dd3eaa4..af9c986be6f8e7 100644
--- a/clang/lib/CodeGen/SanitizerMetadata.cpp
+++ b/clang/lib/CodeGen/SanitizerMetadata.cpp
@@ -91,8 +91,8 @@ void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
return NoSanitizeMask;
};
- reportGlobalToASan(GV, D.getLocation(), QualName, D.getType(), getNoSanitizeMask(D),
- IsDynInit);
+ reportGlobalToASan(GV, D.getLocation(), QualName, D.getType(),
+ getNoSanitizeMask(D), IsDynInit);
}
void SanitizerMetadata::reportGlobalToTySan(llvm::GlobalVariable *GV,
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index e826cd627693f4..c9b412cde4cf03 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -37,8 +37,8 @@ static const SanitizerMask NotAllowedWithMinimalRuntime = SanitizerKind::Vptr;
static const SanitizerMask NotAllowedWithExecuteOnly =
SanitizerKind::Function | SanitizerKind::KCFI;
static const SanitizerMask NeedsUnwindTables =
- SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Type | SanitizerKind::Thread |
- SanitizerKind::Memory | SanitizerKind::DataFlow |
+ SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Type |
+ SanitizerKind::Thread | SanitizerKind::Memory | SanitizerKind::DataFlow |
SanitizerKind::NumericalStability;
static const SanitizerMask SupportsCoverage =
SanitizerKind::Address | SanitizerKind::HWAddress |
>From 2c3ac3d07f6d8bef0338c84fd73a55dbb80bf58d Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Wed, 27 Nov 2024 20:42:24 +0000
Subject: [PATCH 13/16] !fixup merge reportGlobal again, adjust release notes.
---
clang/docs/ReleaseNotes.rst | 2 +-
clang/lib/CodeGen/CGDecl.cpp | 3 +-
clang/lib/CodeGen/CodeGenModule.cpp | 8 +--
clang/lib/CodeGen/SanitizerMetadata.cpp | 74 ++++++++++++-------------
clang/lib/CodeGen/SanitizerMetadata.h | 13 ++---
5 files changed, 47 insertions(+), 53 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b7bf7b2955dc02..a73a849f4818fe 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1156,7 +1156,7 @@ Sanitizers
for examples.
- Introduced an experimental Type Sanitizer, activated by using the
- -fsanitize=type flag. This sanitizer detects violations of C/C++ type-based
+ ``-fsanitize=type flag. This sanitizer detects violations of C/C++ type-based
aliasing rules.
Python Binding Changes
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index bb9d120c37ca86..47b21bc9f63f04 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -458,8 +458,7 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
LocalDeclMap.find(&D)->second = Address(castedAddr, elemTy, alignment);
CGM.setStaticLocalDeclAddress(&D, castedAddr);
- CGM.getSanitizerMetadata()->reportGlobalToASan(var, D);
- CGM.getSanitizerMetadata()->reportGlobalToTySan(var, D);
+ CGM.getSanitizerMetadata()->reportGlobal(var, D);
// Emit global variable debug descriptor for static vars.
CGDebugInfo *DI = getDebugInfo();
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index a2f6a8a481113d..c1f7d1ba976048 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -5162,7 +5162,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty,
}
if (D)
- SanitizerMD->reportGlobalToASan(GV, *D);
+ SanitizerMD->reportGlobal(GV, *D);
LangAS ExpectedAS =
D ? D->getType().getAddressSpace()
@@ -5728,8 +5728,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
if (NeedsGlobalCtor || NeedsGlobalDtor)
EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor);
- SanitizerMD->reportGlobalToASan(GV, *D, NeedsGlobalCtor);
- SanitizerMD->reportGlobalToTySan(GV, *D);
+ SanitizerMD->reportGlobal(GV, *D, NeedsGlobalCtor);
// Emit global variable debug information.
if (CGDebugInfo *DI = getModuleDebugInfo())
@@ -6619,8 +6618,7 @@ CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S,
if (Entry)
*Entry = GV;
- SanitizerMD->reportGlobalToASan(GV, S->getStrTokenLoc(0), "<string literal>");
- // FIXME: Should we also report to the TySan?
+ SanitizerMD->reportGlobal(GV, S->getStrTokenLoc(0), "<string literal>");
return ConstantAddress(castStringLiteralToDefaultAddressSpace(*this, GV),
GV->getValueType(), Alignment);
diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp
index af9c986be6f8e7..ef13a04deceba8 100644
--- a/clang/lib/CodeGen/SanitizerMetadata.cpp
+++ b/clang/lib/CodeGen/SanitizerMetadata.cpp
@@ -19,9 +19,10 @@ using namespace CodeGen;
SanitizerMetadata::SanitizerMetadata(CodeGenModule &CGM) : CGM(CGM) {}
-static bool isAsanHwasanOrMemTag(const SanitizerSet &SS) {
+static bool isAsanHwasanMemTagOrTysan(const SanitizerSet &SS) {
return SS.hasOneOf(SanitizerKind::Address | SanitizerKind::KernelAddress |
- SanitizerKind::HWAddress | SanitizerKind::MemTag);
+ SanitizerKind::HWAddress | SanitizerKind::MemTag |
+ SanitizerKind::Type);
}
static SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) {
@@ -31,13 +32,13 @@ static SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) {
return Mask;
}
-void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
- SourceLocation Loc, StringRef Name,
- QualType Ty,
- SanitizerMask NoSanitizeAttrMask,
- bool IsDynInit) {
+void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
+ SourceLocation Loc, StringRef Name,
+ QualType Ty,
+ SanitizerMask NoSanitizeAttrMask,
+ bool IsDynInit) {
SanitizerSet FsanitizeArgument = CGM.getLangOpts().Sanitize;
- if (!isAsanHwasanOrMemTag(FsanitizeArgument))
+ if (!isAsanHwasanMemTagOrTysan(FsanitizeArgument))
return;
FsanitizeArgument.Mask = expandKernelSanitizerMasks(FsanitizeArgument.Mask);
@@ -70,11 +71,32 @@ void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
GV, Loc, Ty, "init");
GV->setSanitizerMetadata(Meta);
+
+ if (!CGM.getLangOpts().Sanitize.has(SanitizerKind::Type) ||
+ NoSanitizeAttrMask & SanitizerKind::Type)
+ return;
+
+ llvm::MDNode *TBAAInfo = CGM.getTBAATypeInfo(Ty);
+ if (!TBAAInfo || TBAAInfo == CGM.getTBAATypeInfo(CGM.getContext().CharTy))
+ return;
+
+ llvm::Metadata *GlobalMetadata[] = {llvm::ConstantAsMetadata::get(GV),
+ TBAAInfo};
+
+ // Metadata for the global already registered.
+ if (llvm::MDNode::getIfExists(CGM.getLLVMContext(), GlobalMetadata))
+ return;
+
+ llvm::MDNode *ThisGlobal =
+ llvm::MDNode::get(CGM.getLLVMContext(), GlobalMetadata);
+ llvm::NamedMDNode *TysanGlobals =
+ CGM.getModule().getOrInsertNamedMetadata("llvm.tysan.globals");
+ TysanGlobals->addOperand(ThisGlobal);
}
-void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
- const VarDecl &D, bool IsDynInit) {
- if (!isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize))
+void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
+ bool IsDynInit) {
+ if (!isAsanHwasanMemTagOrTysan(CGM.getLangOpts().Sanitize))
return;
std::string QualName;
llvm::raw_string_ostream OS(QualName);
@@ -91,34 +113,10 @@ void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
return NoSanitizeMask;
};
- reportGlobalToASan(GV, D.getLocation(), QualName, 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);
+ reportGlobal(GV, D.getLocation(), QualName, D.getType(), getNoSanitizeMask(D),
+ IsDynInit);
}
void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {
- reportGlobalToASan(GV, SourceLocation(), "", QualType(), SanitizerKind::All);
+ reportGlobal(GV, SourceLocation(), "", QualType(), SanitizerKind::All);
}
diff --git a/clang/lib/CodeGen/SanitizerMetadata.h b/clang/lib/CodeGen/SanitizerMetadata.h
index 9de087c518c6ad..000f02cf8dcf11 100644
--- a/clang/lib/CodeGen/SanitizerMetadata.h
+++ b/clang/lib/CodeGen/SanitizerMetadata.h
@@ -37,13 +37,12 @@ class SanitizerMetadata {
public:
SanitizerMetadata(CodeGenModule &CGM);
- 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 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 disableSanitizerForGlobal(llvm::GlobalVariable *GV);
};
} // end namespace CodeGen
>From bac1590f7350277d6538dfceeded9cadadbb2958 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Wed, 27 Nov 2024 20:53:32 +0000
Subject: [PATCH 14/16] !fixup add missing ``
---
clang/docs/ReleaseNotes.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a73a849f4818fe..3fd1af31c0e8e2 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1156,7 +1156,7 @@ Sanitizers
for examples.
- Introduced an experimental Type Sanitizer, activated by using the
- ``-fsanitize=type flag. This sanitizer detects violations of C/C++ type-based
+ ``-fsanitize=type`` flag. This sanitizer detects violations of C/C++ type-based
aliasing rules.
Python Binding Changes
>From 8dfaca81c8286385713afe33961efc7baf1a3ff1 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 6 Dec 2024 11:46:31 +0000
Subject: [PATCH 15/16] !fixup undo unrelated changes, fix runtimes to push
---
clang/lib/Driver/ToolChains/CommonArgs.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index cb545b6def92c7..b393049669aa30 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -1445,10 +1445,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
if (SanArgs.needsScudoRt()) {
SharedRuntimes.push_back("scudo_standalone");
}
- if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes())
+ if (SanArgs.needsTsanRt())
SharedRuntimes.push_back("tsan");
if (SanArgs.needsTysanRt())
- StaticRuntimes.push_back("tysan");
+ SharedRuntimes.push_back("tysan");
if (SanArgs.needsHwasanRt()) {
if (SanArgs.needsHwasanAliasesRt())
SharedRuntimes.push_back("hwasan_aliases");
>From 13c4092708f82809aeec5320c093387aa4e17993 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 10 Dec 2024 12:18:03 +0000
Subject: [PATCH 16/16] !fixup account for globals without types.
---
clang/lib/CodeGen/SanitizerMetadata.cpp | 2 +-
clang/test/CodeGen/sanitize-type-attr.cpp | 11 +++++++++++
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp
index ef13a04deceba8..e7a88cf5646ef3 100644
--- a/clang/lib/CodeGen/SanitizerMetadata.cpp
+++ b/clang/lib/CodeGen/SanitizerMetadata.cpp
@@ -72,7 +72,7 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
GV->setSanitizerMetadata(Meta);
- if (!CGM.getLangOpts().Sanitize.has(SanitizerKind::Type) ||
+ if (Ty.isNull() || !CGM.getLangOpts().Sanitize.has(SanitizerKind::Type) ||
NoSanitizeAttrMask & SanitizerKind::Type)
return;
diff --git a/clang/test/CodeGen/sanitize-type-attr.cpp b/clang/test/CodeGen/sanitize-type-attr.cpp
index 4da8488e1f9486..eaae9aa98a47a4 100644
--- a/clang/test/CodeGen/sanitize-type-attr.cpp
+++ b/clang/test/CodeGen/sanitize-type-attr.cpp
@@ -57,6 +57,17 @@ struct SX {
};
SX sx;
+void consumer(const char *);
+
+void char_caller() {
+ // TYSAN: void @_Z11char_callerv()
+ // TYSAN-NEXT: entry:
+ // TYSAN-NEXT: call void @_Z8consumerPKc(ptr noundef @.str)
+ // TYSAN-NEXT: ret void
+
+ consumer("foo");
+}
+
// WITHOUT: attributes [[NOATTR]] = { noinline nounwind{{.*}} }
// BL: attributes [[NOATTR]] = { noinline nounwind{{.*}} }
More information about the llvm-commits
mailing list