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