Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
35266 views
//===- HWAddressSanitizer.cpp - memory access error detector --------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8/// \file9/// This file is a part of HWAddressSanitizer, an address basic correctness10/// checker based on tagged addressing.11//===----------------------------------------------------------------------===//1213#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"14#include "llvm/ADT/MapVector.h"15#include "llvm/ADT/STLExtras.h"16#include "llvm/ADT/SmallVector.h"17#include "llvm/ADT/Statistic.h"18#include "llvm/ADT/StringExtras.h"19#include "llvm/ADT/StringRef.h"20#include "llvm/Analysis/BlockFrequencyInfo.h"21#include "llvm/Analysis/DomTreeUpdater.h"22#include "llvm/Analysis/GlobalsModRef.h"23#include "llvm/Analysis/OptimizationRemarkEmitter.h"24#include "llvm/Analysis/PostDominators.h"25#include "llvm/Analysis/ProfileSummaryInfo.h"26#include "llvm/Analysis/StackSafetyAnalysis.h"27#include "llvm/Analysis/TargetLibraryInfo.h"28#include "llvm/Analysis/ValueTracking.h"29#include "llvm/BinaryFormat/Dwarf.h"30#include "llvm/BinaryFormat/ELF.h"31#include "llvm/IR/Attributes.h"32#include "llvm/IR/BasicBlock.h"33#include "llvm/IR/Constant.h"34#include "llvm/IR/Constants.h"35#include "llvm/IR/DataLayout.h"36#include "llvm/IR/DebugInfoMetadata.h"37#include "llvm/IR/DerivedTypes.h"38#include "llvm/IR/Dominators.h"39#include "llvm/IR/Function.h"40#include "llvm/IR/IRBuilder.h"41#include "llvm/IR/InlineAsm.h"42#include "llvm/IR/InstIterator.h"43#include "llvm/IR/Instruction.h"44#include "llvm/IR/Instructions.h"45#include "llvm/IR/IntrinsicInst.h"46#include "llvm/IR/Intrinsics.h"47#include "llvm/IR/LLVMContext.h"48#include "llvm/IR/MDBuilder.h"49#include "llvm/IR/Module.h"50#include "llvm/IR/Type.h"51#include "llvm/IR/Value.h"52#include "llvm/Support/Casting.h"53#include "llvm/Support/CommandLine.h"54#include "llvm/Support/Debug.h"55#include "llvm/Support/MD5.h"56#include "llvm/Support/RandomNumberGenerator.h"57#include "llvm/Support/raw_ostream.h"58#include "llvm/TargetParser/Triple.h"59#include "llvm/Transforms/Instrumentation/AddressSanitizerCommon.h"60#include "llvm/Transforms/Utils/BasicBlockUtils.h"61#include "llvm/Transforms/Utils/Local.h"62#include "llvm/Transforms/Utils/MemoryTaggingSupport.h"63#include "llvm/Transforms/Utils/ModuleUtils.h"64#include "llvm/Transforms/Utils/PromoteMemToReg.h"65#include <optional>66#include <random>6768using namespace llvm;6970#define DEBUG_TYPE "hwasan"7172const char kHwasanModuleCtorName[] = "hwasan.module_ctor";73const char kHwasanNoteName[] = "hwasan.note";74const char kHwasanInitName[] = "__hwasan_init";75const char kHwasanPersonalityThunkName[] = "__hwasan_personality_thunk";7677const char kHwasanShadowMemoryDynamicAddress[] =78"__hwasan_shadow_memory_dynamic_address";7980// Accesses sizes are powers of two: 1, 2, 4, 8, 16.81static const size_t kNumberOfAccessSizes = 5;8283static const size_t kDefaultShadowScale = 4;84static const uint64_t kDynamicShadowSentinel =85std::numeric_limits<uint64_t>::max();8687static const unsigned kShadowBaseAlignment = 32;8889static cl::opt<std::string>90ClMemoryAccessCallbackPrefix("hwasan-memory-access-callback-prefix",91cl::desc("Prefix for memory access callbacks"),92cl::Hidden, cl::init("__hwasan_"));9394static cl::opt<bool> ClKasanMemIntrinCallbackPrefix(95"hwasan-kernel-mem-intrinsic-prefix",96cl::desc("Use prefix for memory intrinsics in KASAN mode"), cl::Hidden,97cl::init(false));9899static cl::opt<bool> ClInstrumentWithCalls(100"hwasan-instrument-with-calls",101cl::desc("instrument reads and writes with callbacks"), cl::Hidden,102cl::init(false));103104static cl::opt<bool> ClInstrumentReads("hwasan-instrument-reads",105cl::desc("instrument read instructions"),106cl::Hidden, cl::init(true));107108static cl::opt<bool>109ClInstrumentWrites("hwasan-instrument-writes",110cl::desc("instrument write instructions"), cl::Hidden,111cl::init(true));112113static cl::opt<bool> ClInstrumentAtomics(114"hwasan-instrument-atomics",115cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden,116cl::init(true));117118static cl::opt<bool> ClInstrumentByval("hwasan-instrument-byval",119cl::desc("instrument byval arguments"),120cl::Hidden, cl::init(true));121122static cl::opt<bool>123ClRecover("hwasan-recover",124cl::desc("Enable recovery mode (continue-after-error)."),125cl::Hidden, cl::init(false));126127static cl::opt<bool> ClInstrumentStack("hwasan-instrument-stack",128cl::desc("instrument stack (allocas)"),129cl::Hidden, cl::init(true));130131static cl::opt<bool>132ClUseStackSafety("hwasan-use-stack-safety", cl::Hidden, cl::init(true),133cl::Hidden, cl::desc("Use Stack Safety analysis results"),134cl::Optional);135136static cl::opt<size_t> ClMaxLifetimes(137"hwasan-max-lifetimes-for-alloca", cl::Hidden, cl::init(3),138cl::ReallyHidden,139cl::desc("How many lifetime ends to handle for a single alloca."),140cl::Optional);141142static cl::opt<bool>143ClUseAfterScope("hwasan-use-after-scope",144cl::desc("detect use after scope within function"),145cl::Hidden, cl::init(true));146147static cl::opt<bool> ClGenerateTagsWithCalls(148"hwasan-generate-tags-with-calls",149cl::desc("generate new tags with runtime library calls"), cl::Hidden,150cl::init(false));151152static cl::opt<bool> ClGlobals("hwasan-globals", cl::desc("Instrument globals"),153cl::Hidden, cl::init(false));154155static cl::opt<int> ClMatchAllTag(156"hwasan-match-all-tag",157cl::desc("don't report bad accesses via pointers with this tag"),158cl::Hidden, cl::init(-1));159160static cl::opt<bool>161ClEnableKhwasan("hwasan-kernel",162cl::desc("Enable KernelHWAddressSanitizer instrumentation"),163cl::Hidden, cl::init(false));164165// These flags allow to change the shadow mapping and control how shadow memory166// is accessed. The shadow mapping looks like:167// Shadow = (Mem >> scale) + offset168169static cl::opt<uint64_t>170ClMappingOffset("hwasan-mapping-offset",171cl::desc("HWASan shadow mapping offset [EXPERIMENTAL]"),172cl::Hidden, cl::init(0));173174static cl::opt<bool>175ClWithIfunc("hwasan-with-ifunc",176cl::desc("Access dynamic shadow through an ifunc global on "177"platforms that support this"),178cl::Hidden, cl::init(false));179180static cl::opt<bool> ClWithTls(181"hwasan-with-tls",182cl::desc("Access dynamic shadow through an thread-local pointer on "183"platforms that support this"),184cl::Hidden, cl::init(true));185186static cl::opt<int> ClHotPercentileCutoff("hwasan-percentile-cutoff-hot",187cl::desc("Hot percentile cuttoff."));188189static cl::opt<float>190ClRandomSkipRate("hwasan-random-rate",191cl::desc("Probability value in the range [0.0, 1.0] "192"to keep instrumentation of a function."));193194STATISTIC(NumTotalFuncs, "Number of total funcs");195STATISTIC(NumInstrumentedFuncs, "Number of instrumented funcs");196STATISTIC(NumNoProfileSummaryFuncs, "Number of funcs without PS");197198// Mode for selecting how to insert frame record info into the stack ring199// buffer.200enum RecordStackHistoryMode {201// Do not record frame record info.202none,203204// Insert instructions into the prologue for storing into the stack ring205// buffer directly.206instr,207208// Add a call to __hwasan_add_frame_record in the runtime.209libcall,210};211212static cl::opt<RecordStackHistoryMode> ClRecordStackHistory(213"hwasan-record-stack-history",214cl::desc("Record stack frames with tagged allocations in a thread-local "215"ring buffer"),216cl::values(clEnumVal(none, "Do not record stack ring history"),217clEnumVal(instr, "Insert instructions into the prologue for "218"storing into the stack ring buffer directly"),219clEnumVal(libcall, "Add a call to __hwasan_add_frame_record for "220"storing into the stack ring buffer")),221cl::Hidden, cl::init(instr));222223static cl::opt<bool>224ClInstrumentMemIntrinsics("hwasan-instrument-mem-intrinsics",225cl::desc("instrument memory intrinsics"),226cl::Hidden, cl::init(true));227228static cl::opt<bool>229ClInstrumentLandingPads("hwasan-instrument-landing-pads",230cl::desc("instrument landing pads"), cl::Hidden,231cl::init(false));232233static cl::opt<bool> ClUseShortGranules(234"hwasan-use-short-granules",235cl::desc("use short granules in allocas and outlined checks"), cl::Hidden,236cl::init(false));237238static cl::opt<bool> ClInstrumentPersonalityFunctions(239"hwasan-instrument-personality-functions",240cl::desc("instrument personality functions"), cl::Hidden);241242static cl::opt<bool> ClInlineAllChecks("hwasan-inline-all-checks",243cl::desc("inline all checks"),244cl::Hidden, cl::init(false));245246static cl::opt<bool> ClInlineFastPathChecks("hwasan-inline-fast-path-checks",247cl::desc("inline all checks"),248cl::Hidden, cl::init(false));249250// Enabled from clang by "-fsanitize-hwaddress-experimental-aliasing".251static cl::opt<bool> ClUsePageAliases("hwasan-experimental-use-page-aliases",252cl::desc("Use page aliasing in HWASan"),253cl::Hidden, cl::init(false));254255namespace {256257template <typename T> T optOr(cl::opt<T> &Opt, T Other) {258return Opt.getNumOccurrences() ? Opt : Other;259}260261bool shouldUsePageAliases(const Triple &TargetTriple) {262return ClUsePageAliases && TargetTriple.getArch() == Triple::x86_64;263}264265bool shouldInstrumentStack(const Triple &TargetTriple) {266return !shouldUsePageAliases(TargetTriple) && ClInstrumentStack;267}268269bool shouldInstrumentWithCalls(const Triple &TargetTriple) {270return optOr(ClInstrumentWithCalls, TargetTriple.getArch() == Triple::x86_64);271}272273bool mightUseStackSafetyAnalysis(bool DisableOptimization) {274return optOr(ClUseStackSafety, !DisableOptimization);275}276277bool shouldUseStackSafetyAnalysis(const Triple &TargetTriple,278bool DisableOptimization) {279return shouldInstrumentStack(TargetTriple) &&280mightUseStackSafetyAnalysis(DisableOptimization);281}282283bool shouldDetectUseAfterScope(const Triple &TargetTriple) {284return ClUseAfterScope && shouldInstrumentStack(TargetTriple);285}286287/// An instrumentation pass implementing detection of addressability bugs288/// using tagged pointers.289class HWAddressSanitizer {290public:291HWAddressSanitizer(Module &M, bool CompileKernel, bool Recover,292const StackSafetyGlobalInfo *SSI)293: M(M), SSI(SSI) {294this->Recover = optOr(ClRecover, Recover);295this->CompileKernel = optOr(ClEnableKhwasan, CompileKernel);296this->Rng = ClRandomSkipRate.getNumOccurrences() ? M.createRNG(DEBUG_TYPE)297: nullptr;298299initializeModule();300}301302void sanitizeFunction(Function &F, FunctionAnalysisManager &FAM);303304private:305struct ShadowTagCheckInfo {306Instruction *TagMismatchTerm = nullptr;307Value *PtrLong = nullptr;308Value *AddrLong = nullptr;309Value *PtrTag = nullptr;310Value *MemTag = nullptr;311};312313bool selectiveInstrumentationShouldSkip(Function &F,314FunctionAnalysisManager &FAM) const;315void initializeModule();316void createHwasanCtorComdat();317318void initializeCallbacks(Module &M);319320Value *getOpaqueNoopCast(IRBuilder<> &IRB, Value *Val);321322Value *getDynamicShadowIfunc(IRBuilder<> &IRB);323Value *getShadowNonTls(IRBuilder<> &IRB);324325void untagPointerOperand(Instruction *I, Value *Addr);326Value *memToShadow(Value *Shadow, IRBuilder<> &IRB);327328int64_t getAccessInfo(bool IsWrite, unsigned AccessSizeIndex);329ShadowTagCheckInfo insertShadowTagCheck(Value *Ptr, Instruction *InsertBefore,330DomTreeUpdater &DTU, LoopInfo *LI);331void instrumentMemAccessOutline(Value *Ptr, bool IsWrite,332unsigned AccessSizeIndex,333Instruction *InsertBefore,334DomTreeUpdater &DTU, LoopInfo *LI);335void instrumentMemAccessInline(Value *Ptr, bool IsWrite,336unsigned AccessSizeIndex,337Instruction *InsertBefore, DomTreeUpdater &DTU,338LoopInfo *LI);339bool ignoreMemIntrinsic(OptimizationRemarkEmitter &ORE, MemIntrinsic *MI);340void instrumentMemIntrinsic(MemIntrinsic *MI);341bool instrumentMemAccess(InterestingMemoryOperand &O, DomTreeUpdater &DTU,342LoopInfo *LI);343bool ignoreAccessWithoutRemark(Instruction *Inst, Value *Ptr);344bool ignoreAccess(OptimizationRemarkEmitter &ORE, Instruction *Inst,345Value *Ptr);346347void getInterestingMemoryOperands(348OptimizationRemarkEmitter &ORE, Instruction *I,349const TargetLibraryInfo &TLI,350SmallVectorImpl<InterestingMemoryOperand> &Interesting);351352void tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag, size_t Size);353Value *tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong, Value *Tag);354Value *untagPointer(IRBuilder<> &IRB, Value *PtrLong);355bool instrumentStack(memtag::StackInfo &Info, Value *StackTag, Value *UARTag,356const DominatorTree &DT, const PostDominatorTree &PDT,357const LoopInfo &LI);358bool instrumentLandingPads(SmallVectorImpl<Instruction *> &RetVec);359Value *getNextTagWithCall(IRBuilder<> &IRB);360Value *getStackBaseTag(IRBuilder<> &IRB);361Value *getAllocaTag(IRBuilder<> &IRB, Value *StackTag, unsigned AllocaNo);362Value *getUARTag(IRBuilder<> &IRB);363364Value *getHwasanThreadSlotPtr(IRBuilder<> &IRB);365Value *applyTagMask(IRBuilder<> &IRB, Value *OldTag);366unsigned retagMask(unsigned AllocaNo);367368void emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord);369370void instrumentGlobal(GlobalVariable *GV, uint8_t Tag);371void instrumentGlobals();372373Value *getCachedFP(IRBuilder<> &IRB);374Value *getFrameRecordInfo(IRBuilder<> &IRB);375376void instrumentPersonalityFunctions();377378LLVMContext *C;379Module &M;380const StackSafetyGlobalInfo *SSI;381Triple TargetTriple;382std::unique_ptr<RandomNumberGenerator> Rng;383384/// This struct defines the shadow mapping using the rule:385/// shadow = (mem >> Scale) + Offset.386/// If InGlobal is true, then387/// extern char __hwasan_shadow[];388/// shadow = (mem >> Scale) + &__hwasan_shadow389/// If InTls is true, then390/// extern char *__hwasan_tls;391/// shadow = (mem>>Scale) + align_up(__hwasan_shadow, kShadowBaseAlignment)392///393/// If WithFrameRecord is true, then __hwasan_tls will be used to access the394/// ring buffer for storing stack allocations on targets that support it.395struct ShadowMapping {396uint8_t Scale;397uint64_t Offset;398bool InGlobal;399bool InTls;400bool WithFrameRecord;401402void init(Triple &TargetTriple, bool InstrumentWithCalls);403Align getObjectAlignment() const { return Align(1ULL << Scale); }404};405406ShadowMapping Mapping;407408Type *VoidTy = Type::getVoidTy(M.getContext());409Type *IntptrTy = M.getDataLayout().getIntPtrType(M.getContext());410PointerType *PtrTy = PointerType::getUnqual(M.getContext());411Type *Int8Ty = Type::getInt8Ty(M.getContext());412Type *Int32Ty = Type::getInt32Ty(M.getContext());413Type *Int64Ty = Type::getInt64Ty(M.getContext());414415bool CompileKernel;416bool Recover;417bool OutlinedChecks;418bool InlineFastPath;419bool UseShortGranules;420bool InstrumentLandingPads;421bool InstrumentWithCalls;422bool InstrumentStack;423bool InstrumentGlobals;424bool DetectUseAfterScope;425bool UsePageAliases;426bool UseMatchAllCallback;427428std::optional<uint8_t> MatchAllTag;429430unsigned PointerTagShift;431uint64_t TagMaskByte;432433Function *HwasanCtorFunction;434435FunctionCallee HwasanMemoryAccessCallback[2][kNumberOfAccessSizes];436FunctionCallee HwasanMemoryAccessCallbackSized[2];437438FunctionCallee HwasanMemmove, HwasanMemcpy, HwasanMemset;439FunctionCallee HwasanHandleVfork;440441FunctionCallee HwasanTagMemoryFunc;442FunctionCallee HwasanGenerateTagFunc;443FunctionCallee HwasanRecordFrameRecordFunc;444445Constant *ShadowGlobal;446447Value *ShadowBase = nullptr;448Value *StackBaseTag = nullptr;449Value *CachedFP = nullptr;450GlobalValue *ThreadPtrGlobal = nullptr;451};452453} // end anonymous namespace454455PreservedAnalyses HWAddressSanitizerPass::run(Module &M,456ModuleAnalysisManager &MAM) {457const StackSafetyGlobalInfo *SSI = nullptr;458auto TargetTriple = llvm::Triple(M.getTargetTriple());459if (shouldUseStackSafetyAnalysis(TargetTriple, Options.DisableOptimization))460SSI = &MAM.getResult<StackSafetyGlobalAnalysis>(M);461462HWAddressSanitizer HWASan(M, Options.CompileKernel, Options.Recover, SSI);463auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();464for (Function &F : M)465HWASan.sanitizeFunction(F, FAM);466467PreservedAnalyses PA = PreservedAnalyses::none();468// DominatorTreeAnalysis, PostDominatorTreeAnalysis, and LoopAnalysis469// are incrementally updated throughout this pass whenever470// SplitBlockAndInsertIfThen is called.471PA.preserve<DominatorTreeAnalysis>();472PA.preserve<PostDominatorTreeAnalysis>();473PA.preserve<LoopAnalysis>();474// GlobalsAA is considered stateless and does not get invalidated unless475// explicitly invalidated; PreservedAnalyses::none() is not enough. Sanitizers476// make changes that require GlobalsAA to be invalidated.477PA.abandon<GlobalsAA>();478return PA;479}480void HWAddressSanitizerPass::printPipeline(481raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {482static_cast<PassInfoMixin<HWAddressSanitizerPass> *>(this)->printPipeline(483OS, MapClassName2PassName);484OS << '<';485if (Options.CompileKernel)486OS << "kernel;";487if (Options.Recover)488OS << "recover";489OS << '>';490}491492void HWAddressSanitizer::createHwasanCtorComdat() {493std::tie(HwasanCtorFunction, std::ignore) =494getOrCreateSanitizerCtorAndInitFunctions(495M, kHwasanModuleCtorName, kHwasanInitName,496/*InitArgTypes=*/{},497/*InitArgs=*/{},498// This callback is invoked when the functions are created the first499// time. Hook them into the global ctors list in that case:500[&](Function *Ctor, FunctionCallee) {501Comdat *CtorComdat = M.getOrInsertComdat(kHwasanModuleCtorName);502Ctor->setComdat(CtorComdat);503appendToGlobalCtors(M, Ctor, 0, Ctor);504});505506// Create a note that contains pointers to the list of global507// descriptors. Adding a note to the output file will cause the linker to508// create a PT_NOTE program header pointing to the note that we can use to509// find the descriptor list starting from the program headers. A function510// provided by the runtime initializes the shadow memory for the globals by511// accessing the descriptor list via the note. The dynamic loader needs to512// call this function whenever a library is loaded.513//514// The reason why we use a note for this instead of a more conventional515// approach of having a global constructor pass a descriptor list pointer to516// the runtime is because of an order of initialization problem. With517// constructors we can encounter the following problematic scenario:518//519// 1) library A depends on library B and also interposes one of B's symbols520// 2) B's constructors are called before A's (as required for correctness)521// 3) during construction, B accesses one of its "own" globals (actually522// interposed by A) and triggers a HWASAN failure due to the initialization523// for A not having happened yet524//525// Even without interposition it is possible to run into similar situations in526// cases where two libraries mutually depend on each other.527//528// We only need one note per binary, so put everything for the note in a529// comdat. This needs to be a comdat with an .init_array section to prevent530// newer versions of lld from discarding the note.531//532// Create the note even if we aren't instrumenting globals. This ensures that533// binaries linked from object files with both instrumented and534// non-instrumented globals will end up with a note, even if a comdat from an535// object file with non-instrumented globals is selected. The note is harmless536// if the runtime doesn't support it, since it will just be ignored.537Comdat *NoteComdat = M.getOrInsertComdat(kHwasanModuleCtorName);538539Type *Int8Arr0Ty = ArrayType::get(Int8Ty, 0);540auto *Start =541new GlobalVariable(M, Int8Arr0Ty, true, GlobalVariable::ExternalLinkage,542nullptr, "__start_hwasan_globals");543Start->setVisibility(GlobalValue::HiddenVisibility);544auto *Stop =545new GlobalVariable(M, Int8Arr0Ty, true, GlobalVariable::ExternalLinkage,546nullptr, "__stop_hwasan_globals");547Stop->setVisibility(GlobalValue::HiddenVisibility);548549// Null-terminated so actually 8 bytes, which are required in order to align550// the note properly.551auto *Name = ConstantDataArray::get(*C, "LLVM\0\0\0");552553auto *NoteTy = StructType::get(Int32Ty, Int32Ty, Int32Ty, Name->getType(),554Int32Ty, Int32Ty);555auto *Note =556new GlobalVariable(M, NoteTy, /*isConstant=*/true,557GlobalValue::PrivateLinkage, nullptr, kHwasanNoteName);558Note->setSection(".note.hwasan.globals");559Note->setComdat(NoteComdat);560Note->setAlignment(Align(4));561562// The pointers in the note need to be relative so that the note ends up being563// placed in rodata, which is the standard location for notes.564auto CreateRelPtr = [&](Constant *Ptr) {565return ConstantExpr::getTrunc(566ConstantExpr::getSub(ConstantExpr::getPtrToInt(Ptr, Int64Ty),567ConstantExpr::getPtrToInt(Note, Int64Ty)),568Int32Ty);569};570Note->setInitializer(ConstantStruct::getAnon(571{ConstantInt::get(Int32Ty, 8), // n_namesz572ConstantInt::get(Int32Ty, 8), // n_descsz573ConstantInt::get(Int32Ty, ELF::NT_LLVM_HWASAN_GLOBALS), // n_type574Name, CreateRelPtr(Start), CreateRelPtr(Stop)}));575appendToCompilerUsed(M, Note);576577// Create a zero-length global in hwasan_globals so that the linker will578// always create start and stop symbols.579auto *Dummy = new GlobalVariable(580M, Int8Arr0Ty, /*isConstantGlobal*/ true, GlobalVariable::PrivateLinkage,581Constant::getNullValue(Int8Arr0Ty), "hwasan.dummy.global");582Dummy->setSection("hwasan_globals");583Dummy->setComdat(NoteComdat);584Dummy->setMetadata(LLVMContext::MD_associated,585MDNode::get(*C, ValueAsMetadata::get(Note)));586appendToCompilerUsed(M, Dummy);587}588589/// Module-level initialization.590///591/// inserts a call to __hwasan_init to the module's constructor list.592void HWAddressSanitizer::initializeModule() {593LLVM_DEBUG(dbgs() << "Init " << M.getName() << "\n");594TargetTriple = Triple(M.getTargetTriple());595596// x86_64 currently has two modes:597// - Intel LAM (default)598// - pointer aliasing (heap only)599bool IsX86_64 = TargetTriple.getArch() == Triple::x86_64;600UsePageAliases = shouldUsePageAliases(TargetTriple);601InstrumentWithCalls = shouldInstrumentWithCalls(TargetTriple);602InstrumentStack = shouldInstrumentStack(TargetTriple);603DetectUseAfterScope = shouldDetectUseAfterScope(TargetTriple);604PointerTagShift = IsX86_64 ? 57 : 56;605TagMaskByte = IsX86_64 ? 0x3F : 0xFF;606607Mapping.init(TargetTriple, InstrumentWithCalls);608609C = &(M.getContext());610IRBuilder<> IRB(*C);611612HwasanCtorFunction = nullptr;613614// Older versions of Android do not have the required runtime support for615// short granules, global or personality function instrumentation. On other616// platforms we currently require using the latest version of the runtime.617bool NewRuntime =618!TargetTriple.isAndroid() || !TargetTriple.isAndroidVersionLT(30);619620UseShortGranules = optOr(ClUseShortGranules, NewRuntime);621OutlinedChecks = (TargetTriple.isAArch64() || TargetTriple.isRISCV64()) &&622TargetTriple.isOSBinFormatELF() &&623!optOr(ClInlineAllChecks, Recover);624625// These platforms may prefer less inlining to reduce binary size.626InlineFastPath = optOr(ClInlineFastPathChecks, !(TargetTriple.isAndroid() ||627TargetTriple.isOSFuchsia()));628629if (ClMatchAllTag.getNumOccurrences()) {630if (ClMatchAllTag != -1) {631MatchAllTag = ClMatchAllTag & 0xFF;632}633} else if (CompileKernel) {634MatchAllTag = 0xFF;635}636UseMatchAllCallback = !CompileKernel && MatchAllTag.has_value();637638// If we don't have personality function support, fall back to landing pads.639InstrumentLandingPads = optOr(ClInstrumentLandingPads, !NewRuntime);640641InstrumentGlobals =642!CompileKernel && !UsePageAliases && optOr(ClGlobals, NewRuntime);643644if (!CompileKernel) {645createHwasanCtorComdat();646647if (InstrumentGlobals)648instrumentGlobals();649650bool InstrumentPersonalityFunctions =651optOr(ClInstrumentPersonalityFunctions, NewRuntime);652if (InstrumentPersonalityFunctions)653instrumentPersonalityFunctions();654}655656if (!TargetTriple.isAndroid()) {657Constant *C = M.getOrInsertGlobal("__hwasan_tls", IntptrTy, [&] {658auto *GV = new GlobalVariable(M, IntptrTy, /*isConstant=*/false,659GlobalValue::ExternalLinkage, nullptr,660"__hwasan_tls", nullptr,661GlobalVariable::InitialExecTLSModel);662appendToCompilerUsed(M, GV);663return GV;664});665ThreadPtrGlobal = cast<GlobalVariable>(C);666}667}668669void HWAddressSanitizer::initializeCallbacks(Module &M) {670IRBuilder<> IRB(*C);671const std::string MatchAllStr = UseMatchAllCallback ? "_match_all" : "";672FunctionType *HwasanMemoryAccessCallbackSizedFnTy,673*HwasanMemoryAccessCallbackFnTy, *HwasanMemTransferFnTy,674*HwasanMemsetFnTy;675if (UseMatchAllCallback) {676HwasanMemoryAccessCallbackSizedFnTy =677FunctionType::get(VoidTy, {IntptrTy, IntptrTy, Int8Ty}, false);678HwasanMemoryAccessCallbackFnTy =679FunctionType::get(VoidTy, {IntptrTy, Int8Ty}, false);680HwasanMemTransferFnTy =681FunctionType::get(PtrTy, {PtrTy, PtrTy, IntptrTy, Int8Ty}, false);682HwasanMemsetFnTy =683FunctionType::get(PtrTy, {PtrTy, Int32Ty, IntptrTy, Int8Ty}, false);684} else {685HwasanMemoryAccessCallbackSizedFnTy =686FunctionType::get(VoidTy, {IntptrTy, IntptrTy}, false);687HwasanMemoryAccessCallbackFnTy =688FunctionType::get(VoidTy, {IntptrTy}, false);689HwasanMemTransferFnTy =690FunctionType::get(PtrTy, {PtrTy, PtrTy, IntptrTy}, false);691HwasanMemsetFnTy =692FunctionType::get(PtrTy, {PtrTy, Int32Ty, IntptrTy}, false);693}694695for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {696const std::string TypeStr = AccessIsWrite ? "store" : "load";697const std::string EndingStr = Recover ? "_noabort" : "";698699HwasanMemoryAccessCallbackSized[AccessIsWrite] = M.getOrInsertFunction(700ClMemoryAccessCallbackPrefix + TypeStr + "N" + MatchAllStr + EndingStr,701HwasanMemoryAccessCallbackSizedFnTy);702703for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;704AccessSizeIndex++) {705HwasanMemoryAccessCallback[AccessIsWrite][AccessSizeIndex] =706M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + TypeStr +707itostr(1ULL << AccessSizeIndex) +708MatchAllStr + EndingStr,709HwasanMemoryAccessCallbackFnTy);710}711}712713const std::string MemIntrinCallbackPrefix =714(CompileKernel && !ClKasanMemIntrinCallbackPrefix)715? std::string("")716: ClMemoryAccessCallbackPrefix;717718HwasanMemmove = M.getOrInsertFunction(719MemIntrinCallbackPrefix + "memmove" + MatchAllStr, HwasanMemTransferFnTy);720HwasanMemcpy = M.getOrInsertFunction(721MemIntrinCallbackPrefix + "memcpy" + MatchAllStr, HwasanMemTransferFnTy);722HwasanMemset = M.getOrInsertFunction(723MemIntrinCallbackPrefix + "memset" + MatchAllStr, HwasanMemsetFnTy);724725HwasanTagMemoryFunc = M.getOrInsertFunction("__hwasan_tag_memory", VoidTy,726PtrTy, Int8Ty, IntptrTy);727HwasanGenerateTagFunc =728M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty);729730HwasanRecordFrameRecordFunc =731M.getOrInsertFunction("__hwasan_add_frame_record", VoidTy, Int64Ty);732733ShadowGlobal =734M.getOrInsertGlobal("__hwasan_shadow", ArrayType::get(Int8Ty, 0));735736HwasanHandleVfork =737M.getOrInsertFunction("__hwasan_handle_vfork", VoidTy, IntptrTy);738}739740Value *HWAddressSanitizer::getOpaqueNoopCast(IRBuilder<> &IRB, Value *Val) {741// An empty inline asm with input reg == output reg.742// An opaque no-op cast, basically.743// This prevents code bloat as a result of rematerializing trivial definitions744// such as constants or global addresses at every load and store.745InlineAsm *Asm =746InlineAsm::get(FunctionType::get(PtrTy, {Val->getType()}, false),747StringRef(""), StringRef("=r,0"),748/*hasSideEffects=*/false);749return IRB.CreateCall(Asm, {Val}, ".hwasan.shadow");750}751752Value *HWAddressSanitizer::getDynamicShadowIfunc(IRBuilder<> &IRB) {753return getOpaqueNoopCast(IRB, ShadowGlobal);754}755756Value *HWAddressSanitizer::getShadowNonTls(IRBuilder<> &IRB) {757if (Mapping.Offset != kDynamicShadowSentinel)758return getOpaqueNoopCast(759IRB, ConstantExpr::getIntToPtr(760ConstantInt::get(IntptrTy, Mapping.Offset), PtrTy));761762if (Mapping.InGlobal)763return getDynamicShadowIfunc(IRB);764765Value *GlobalDynamicAddress =766IRB.GetInsertBlock()->getParent()->getParent()->getOrInsertGlobal(767kHwasanShadowMemoryDynamicAddress, PtrTy);768return IRB.CreateLoad(PtrTy, GlobalDynamicAddress);769}770771bool HWAddressSanitizer::ignoreAccessWithoutRemark(Instruction *Inst,772Value *Ptr) {773// Do not instrument accesses from different address spaces; we cannot deal774// with them.775Type *PtrTy = cast<PointerType>(Ptr->getType()->getScalarType());776if (PtrTy->getPointerAddressSpace() != 0)777return true;778779// Ignore swifterror addresses.780// swifterror memory addresses are mem2reg promoted by instruction781// selection. As such they cannot have regular uses like an instrumentation782// function and it makes no sense to track them as memory.783if (Ptr->isSwiftError())784return true;785786if (findAllocaForValue(Ptr)) {787if (!InstrumentStack)788return true;789if (SSI && SSI->stackAccessIsSafe(*Inst))790return true;791}792793if (isa<GlobalVariable>(getUnderlyingObject(Ptr))) {794if (!InstrumentGlobals)795return true;796// TODO: Optimize inbound global accesses, like Asan `instrumentMop`.797}798799return false;800}801802bool HWAddressSanitizer::ignoreAccess(OptimizationRemarkEmitter &ORE,803Instruction *Inst, Value *Ptr) {804bool Ignored = ignoreAccessWithoutRemark(Inst, Ptr);805if (Ignored) {806ORE.emit(807[&]() { return OptimizationRemark(DEBUG_TYPE, "ignoreAccess", Inst); });808} else {809ORE.emit([&]() {810return OptimizationRemarkMissed(DEBUG_TYPE, "ignoreAccess", Inst);811});812}813return Ignored;814}815816void HWAddressSanitizer::getInterestingMemoryOperands(817OptimizationRemarkEmitter &ORE, Instruction *I,818const TargetLibraryInfo &TLI,819SmallVectorImpl<InterestingMemoryOperand> &Interesting) {820// Skip memory accesses inserted by another instrumentation.821if (I->hasMetadata(LLVMContext::MD_nosanitize))822return;823824// Do not instrument the load fetching the dynamic shadow address.825if (ShadowBase == I)826return;827828if (LoadInst *LI = dyn_cast<LoadInst>(I)) {829if (!ClInstrumentReads || ignoreAccess(ORE, I, LI->getPointerOperand()))830return;831Interesting.emplace_back(I, LI->getPointerOperandIndex(), false,832LI->getType(), LI->getAlign());833} else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {834if (!ClInstrumentWrites || ignoreAccess(ORE, I, SI->getPointerOperand()))835return;836Interesting.emplace_back(I, SI->getPointerOperandIndex(), true,837SI->getValueOperand()->getType(), SI->getAlign());838} else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {839if (!ClInstrumentAtomics || ignoreAccess(ORE, I, RMW->getPointerOperand()))840return;841Interesting.emplace_back(I, RMW->getPointerOperandIndex(), true,842RMW->getValOperand()->getType(), std::nullopt);843} else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {844if (!ClInstrumentAtomics || ignoreAccess(ORE, I, XCHG->getPointerOperand()))845return;846Interesting.emplace_back(I, XCHG->getPointerOperandIndex(), true,847XCHG->getCompareOperand()->getType(),848std::nullopt);849} else if (auto *CI = dyn_cast<CallInst>(I)) {850for (unsigned ArgNo = 0; ArgNo < CI->arg_size(); ArgNo++) {851if (!ClInstrumentByval || !CI->isByValArgument(ArgNo) ||852ignoreAccess(ORE, I, CI->getArgOperand(ArgNo)))853continue;854Type *Ty = CI->getParamByValType(ArgNo);855Interesting.emplace_back(I, ArgNo, false, Ty, Align(1));856}857maybeMarkSanitizerLibraryCallNoBuiltin(CI, &TLI);858}859}860861static unsigned getPointerOperandIndex(Instruction *I) {862if (LoadInst *LI = dyn_cast<LoadInst>(I))863return LI->getPointerOperandIndex();864if (StoreInst *SI = dyn_cast<StoreInst>(I))865return SI->getPointerOperandIndex();866if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I))867return RMW->getPointerOperandIndex();868if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I))869return XCHG->getPointerOperandIndex();870report_fatal_error("Unexpected instruction");871return -1;872}873874static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {875size_t Res = llvm::countr_zero(TypeSize / 8);876assert(Res < kNumberOfAccessSizes);877return Res;878}879880void HWAddressSanitizer::untagPointerOperand(Instruction *I, Value *Addr) {881if (TargetTriple.isAArch64() || TargetTriple.getArch() == Triple::x86_64 ||882TargetTriple.isRISCV64())883return;884885IRBuilder<> IRB(I);886Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);887Value *UntaggedPtr =888IRB.CreateIntToPtr(untagPointer(IRB, AddrLong), Addr->getType());889I->setOperand(getPointerOperandIndex(I), UntaggedPtr);890}891892Value *HWAddressSanitizer::memToShadow(Value *Mem, IRBuilder<> &IRB) {893// Mem >> Scale894Value *Shadow = IRB.CreateLShr(Mem, Mapping.Scale);895if (Mapping.Offset == 0)896return IRB.CreateIntToPtr(Shadow, PtrTy);897// (Mem >> Scale) + Offset898return IRB.CreatePtrAdd(ShadowBase, Shadow);899}900901int64_t HWAddressSanitizer::getAccessInfo(bool IsWrite,902unsigned AccessSizeIndex) {903return (CompileKernel << HWASanAccessInfo::CompileKernelShift) |904(MatchAllTag.has_value() << HWASanAccessInfo::HasMatchAllShift) |905(MatchAllTag.value_or(0) << HWASanAccessInfo::MatchAllShift) |906(Recover << HWASanAccessInfo::RecoverShift) |907(IsWrite << HWASanAccessInfo::IsWriteShift) |908(AccessSizeIndex << HWASanAccessInfo::AccessSizeShift);909}910911HWAddressSanitizer::ShadowTagCheckInfo912HWAddressSanitizer::insertShadowTagCheck(Value *Ptr, Instruction *InsertBefore,913DomTreeUpdater &DTU, LoopInfo *LI) {914ShadowTagCheckInfo R;915916IRBuilder<> IRB(InsertBefore);917918R.PtrLong = IRB.CreatePointerCast(Ptr, IntptrTy);919R.PtrTag =920IRB.CreateTrunc(IRB.CreateLShr(R.PtrLong, PointerTagShift), Int8Ty);921R.AddrLong = untagPointer(IRB, R.PtrLong);922Value *Shadow = memToShadow(R.AddrLong, IRB);923R.MemTag = IRB.CreateLoad(Int8Ty, Shadow);924Value *TagMismatch = IRB.CreateICmpNE(R.PtrTag, R.MemTag);925926if (MatchAllTag.has_value()) {927Value *TagNotIgnored = IRB.CreateICmpNE(928R.PtrTag, ConstantInt::get(R.PtrTag->getType(), *MatchAllTag));929TagMismatch = IRB.CreateAnd(TagMismatch, TagNotIgnored);930}931932R.TagMismatchTerm = SplitBlockAndInsertIfThen(933TagMismatch, InsertBefore, false,934MDBuilder(*C).createUnlikelyBranchWeights(), &DTU, LI);935936return R;937}938939void HWAddressSanitizer::instrumentMemAccessOutline(Value *Ptr, bool IsWrite,940unsigned AccessSizeIndex,941Instruction *InsertBefore,942DomTreeUpdater &DTU,943LoopInfo *LI) {944assert(!UsePageAliases);945const int64_t AccessInfo = getAccessInfo(IsWrite, AccessSizeIndex);946947if (InlineFastPath)948InsertBefore =949insertShadowTagCheck(Ptr, InsertBefore, DTU, LI).TagMismatchTerm;950951IRBuilder<> IRB(InsertBefore);952Module *M = IRB.GetInsertBlock()->getParent()->getParent();953bool useFixedShadowIntrinsic = false;954// The memaccess fixed shadow intrinsic is only supported on AArch64,955// which allows a 16-bit immediate to be left-shifted by 32.956// Since kShadowBaseAlignment == 32, and Linux by default will not957// mmap above 48-bits, practically any valid shadow offset is958// representable.959// In particular, an offset of 4TB (1024 << 32) is representable, and960// ought to be good enough for anybody.961if (TargetTriple.isAArch64() && Mapping.Offset != kDynamicShadowSentinel) {962uint16_t offset_shifted = Mapping.Offset >> 32;963useFixedShadowIntrinsic = (uint64_t)offset_shifted << 32 == Mapping.Offset;964}965966if (useFixedShadowIntrinsic)967IRB.CreateCall(968Intrinsic::getDeclaration(969M, UseShortGranules970? Intrinsic::hwasan_check_memaccess_shortgranules_fixedshadow971: Intrinsic::hwasan_check_memaccess_fixedshadow),972{Ptr, ConstantInt::get(Int32Ty, AccessInfo),973ConstantInt::get(Int64Ty, Mapping.Offset)});974else975IRB.CreateCall(Intrinsic::getDeclaration(976M, UseShortGranules977? Intrinsic::hwasan_check_memaccess_shortgranules978: Intrinsic::hwasan_check_memaccess),979{ShadowBase, Ptr, ConstantInt::get(Int32Ty, AccessInfo)});980}981982void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite,983unsigned AccessSizeIndex,984Instruction *InsertBefore,985DomTreeUpdater &DTU,986LoopInfo *LI) {987assert(!UsePageAliases);988const int64_t AccessInfo = getAccessInfo(IsWrite, AccessSizeIndex);989990ShadowTagCheckInfo TCI = insertShadowTagCheck(Ptr, InsertBefore, DTU, LI);991992IRBuilder<> IRB(TCI.TagMismatchTerm);993Value *OutOfShortGranuleTagRange =994IRB.CreateICmpUGT(TCI.MemTag, ConstantInt::get(Int8Ty, 15));995Instruction *CheckFailTerm = SplitBlockAndInsertIfThen(996OutOfShortGranuleTagRange, TCI.TagMismatchTerm, !Recover,997MDBuilder(*C).createUnlikelyBranchWeights(), &DTU, LI);998999IRB.SetInsertPoint(TCI.TagMismatchTerm);1000Value *PtrLowBits = IRB.CreateTrunc(IRB.CreateAnd(TCI.PtrLong, 15), Int8Ty);1001PtrLowBits = IRB.CreateAdd(1002PtrLowBits, ConstantInt::get(Int8Ty, (1 << AccessSizeIndex) - 1));1003Value *PtrLowBitsOOB = IRB.CreateICmpUGE(PtrLowBits, TCI.MemTag);1004SplitBlockAndInsertIfThen(PtrLowBitsOOB, TCI.TagMismatchTerm, false,1005MDBuilder(*C).createUnlikelyBranchWeights(), &DTU,1006LI, CheckFailTerm->getParent());10071008IRB.SetInsertPoint(TCI.TagMismatchTerm);1009Value *InlineTagAddr = IRB.CreateOr(TCI.AddrLong, 15);1010InlineTagAddr = IRB.CreateIntToPtr(InlineTagAddr, PtrTy);1011Value *InlineTag = IRB.CreateLoad(Int8Ty, InlineTagAddr);1012Value *InlineTagMismatch = IRB.CreateICmpNE(TCI.PtrTag, InlineTag);1013SplitBlockAndInsertIfThen(InlineTagMismatch, TCI.TagMismatchTerm, false,1014MDBuilder(*C).createUnlikelyBranchWeights(), &DTU,1015LI, CheckFailTerm->getParent());10161017IRB.SetInsertPoint(CheckFailTerm);1018InlineAsm *Asm;1019switch (TargetTriple.getArch()) {1020case Triple::x86_64:1021// The signal handler will find the data address in rdi.1022Asm = InlineAsm::get(1023FunctionType::get(VoidTy, {TCI.PtrLong->getType()}, false),1024"int3\nnopl " +1025itostr(0x40 + (AccessInfo & HWASanAccessInfo::RuntimeMask)) +1026"(%rax)",1027"{rdi}",1028/*hasSideEffects=*/true);1029break;1030case Triple::aarch64:1031case Triple::aarch64_be:1032// The signal handler will find the data address in x0.1033Asm = InlineAsm::get(1034FunctionType::get(VoidTy, {TCI.PtrLong->getType()}, false),1035"brk #" + itostr(0x900 + (AccessInfo & HWASanAccessInfo::RuntimeMask)),1036"{x0}",1037/*hasSideEffects=*/true);1038break;1039case Triple::riscv64:1040// The signal handler will find the data address in x10.1041Asm = InlineAsm::get(1042FunctionType::get(VoidTy, {TCI.PtrLong->getType()}, false),1043"ebreak\naddiw x0, x11, " +1044itostr(0x40 + (AccessInfo & HWASanAccessInfo::RuntimeMask)),1045"{x10}",1046/*hasSideEffects=*/true);1047break;1048default:1049report_fatal_error("unsupported architecture");1050}1051IRB.CreateCall(Asm, TCI.PtrLong);1052if (Recover)1053cast<BranchInst>(CheckFailTerm)1054->setSuccessor(0, TCI.TagMismatchTerm->getParent());1055}10561057bool HWAddressSanitizer::ignoreMemIntrinsic(OptimizationRemarkEmitter &ORE,1058MemIntrinsic *MI) {1059if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(MI)) {1060return (!ClInstrumentWrites || ignoreAccess(ORE, MTI, MTI->getDest())) &&1061(!ClInstrumentReads || ignoreAccess(ORE, MTI, MTI->getSource()));1062}1063if (isa<MemSetInst>(MI))1064return !ClInstrumentWrites || ignoreAccess(ORE, MI, MI->getDest());1065return false;1066}10671068void HWAddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) {1069IRBuilder<> IRB(MI);1070if (isa<MemTransferInst>(MI)) {1071SmallVector<Value *, 4> Args{1072MI->getOperand(0), MI->getOperand(1),1073IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)};10741075if (UseMatchAllCallback)1076Args.emplace_back(ConstantInt::get(Int8Ty, *MatchAllTag));1077IRB.CreateCall(isa<MemMoveInst>(MI) ? HwasanMemmove : HwasanMemcpy, Args);1078} else if (isa<MemSetInst>(MI)) {1079SmallVector<Value *, 4> Args{1080MI->getOperand(0),1081IRB.CreateIntCast(MI->getOperand(1), IRB.getInt32Ty(), false),1082IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)};1083if (UseMatchAllCallback)1084Args.emplace_back(ConstantInt::get(Int8Ty, *MatchAllTag));1085IRB.CreateCall(HwasanMemset, Args);1086}1087MI->eraseFromParent();1088}10891090bool HWAddressSanitizer::instrumentMemAccess(InterestingMemoryOperand &O,1091DomTreeUpdater &DTU,1092LoopInfo *LI) {1093Value *Addr = O.getPtr();10941095LLVM_DEBUG(dbgs() << "Instrumenting: " << O.getInsn() << "\n");10961097if (O.MaybeMask)1098return false; // FIXME10991100IRBuilder<> IRB(O.getInsn());1101if (!O.TypeStoreSize.isScalable() && isPowerOf2_64(O.TypeStoreSize) &&1102(O.TypeStoreSize / 8 <= (1ULL << (kNumberOfAccessSizes - 1))) &&1103(!O.Alignment || *O.Alignment >= Mapping.getObjectAlignment() ||1104*O.Alignment >= O.TypeStoreSize / 8)) {1105size_t AccessSizeIndex = TypeSizeToSizeIndex(O.TypeStoreSize);1106if (InstrumentWithCalls) {1107SmallVector<Value *, 2> Args{IRB.CreatePointerCast(Addr, IntptrTy)};1108if (UseMatchAllCallback)1109Args.emplace_back(ConstantInt::get(Int8Ty, *MatchAllTag));1110IRB.CreateCall(HwasanMemoryAccessCallback[O.IsWrite][AccessSizeIndex],1111Args);1112} else if (OutlinedChecks) {1113instrumentMemAccessOutline(Addr, O.IsWrite, AccessSizeIndex, O.getInsn(),1114DTU, LI);1115} else {1116instrumentMemAccessInline(Addr, O.IsWrite, AccessSizeIndex, O.getInsn(),1117DTU, LI);1118}1119} else {1120SmallVector<Value *, 3> Args{1121IRB.CreatePointerCast(Addr, IntptrTy),1122IRB.CreateUDiv(IRB.CreateTypeSize(IntptrTy, O.TypeStoreSize),1123ConstantInt::get(IntptrTy, 8))};1124if (UseMatchAllCallback)1125Args.emplace_back(ConstantInt::get(Int8Ty, *MatchAllTag));1126IRB.CreateCall(HwasanMemoryAccessCallbackSized[O.IsWrite], Args);1127}1128untagPointerOperand(O.getInsn(), Addr);11291130return true;1131}11321133void HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag,1134size_t Size) {1135size_t AlignedSize = alignTo(Size, Mapping.getObjectAlignment());1136if (!UseShortGranules)1137Size = AlignedSize;11381139Tag = IRB.CreateTrunc(Tag, Int8Ty);1140if (InstrumentWithCalls) {1141IRB.CreateCall(HwasanTagMemoryFunc,1142{IRB.CreatePointerCast(AI, PtrTy), Tag,1143ConstantInt::get(IntptrTy, AlignedSize)});1144} else {1145size_t ShadowSize = Size >> Mapping.Scale;1146Value *AddrLong = untagPointer(IRB, IRB.CreatePointerCast(AI, IntptrTy));1147Value *ShadowPtr = memToShadow(AddrLong, IRB);1148// If this memset is not inlined, it will be intercepted in the hwasan1149// runtime library. That's OK, because the interceptor skips the checks if1150// the address is in the shadow region.1151// FIXME: the interceptor is not as fast as real memset. Consider lowering1152// llvm.memset right here into either a sequence of stores, or a call to1153// hwasan_tag_memory.1154if (ShadowSize)1155IRB.CreateMemSet(ShadowPtr, Tag, ShadowSize, Align(1));1156if (Size != AlignedSize) {1157const uint8_t SizeRemainder = Size % Mapping.getObjectAlignment().value();1158IRB.CreateStore(ConstantInt::get(Int8Ty, SizeRemainder),1159IRB.CreateConstGEP1_32(Int8Ty, ShadowPtr, ShadowSize));1160IRB.CreateStore(1161Tag, IRB.CreateConstGEP1_32(Int8Ty, IRB.CreatePointerCast(AI, PtrTy),1162AlignedSize - 1));1163}1164}1165}11661167unsigned HWAddressSanitizer::retagMask(unsigned AllocaNo) {1168if (TargetTriple.getArch() == Triple::x86_64)1169return AllocaNo & TagMaskByte;11701171// A list of 8-bit numbers that have at most one run of non-zero bits.1172// x = x ^ (mask << 56) can be encoded as a single armv8 instruction for these1173// masks.1174// The list does not include the value 255, which is used for UAR.1175//1176// Because we are more likely to use earlier elements of this list than later1177// ones, it is sorted in increasing order of probability of collision with a1178// mask allocated (temporally) nearby. The program that generated this list1179// can be found at:1180// https://github.com/google/sanitizers/blob/master/hwaddress-sanitizer/sort_masks.py1181static const unsigned FastMasks[] = {11820, 128, 64, 192, 32, 96, 224, 112, 240, 48, 16, 120,1183248, 56, 24, 8, 124, 252, 60, 28, 12, 4, 126, 254,118462, 30, 14, 6, 2, 127, 63, 31, 15, 7, 3, 1};1185return FastMasks[AllocaNo % std::size(FastMasks)];1186}11871188Value *HWAddressSanitizer::applyTagMask(IRBuilder<> &IRB, Value *OldTag) {1189if (TagMaskByte == 0xFF)1190return OldTag; // No need to clear the tag byte.1191return IRB.CreateAnd(OldTag,1192ConstantInt::get(OldTag->getType(), TagMaskByte));1193}11941195Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) {1196return IRB.CreateZExt(IRB.CreateCall(HwasanGenerateTagFunc), IntptrTy);1197}11981199Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) {1200if (ClGenerateTagsWithCalls)1201return nullptr;1202if (StackBaseTag)1203return StackBaseTag;1204// Extract some entropy from the stack pointer for the tags.1205// Take bits 20..28 (ASLR entropy) and xor with bits 0..8 (these differ1206// between functions).1207Value *FramePointerLong = getCachedFP(IRB);1208Value *StackTag =1209applyTagMask(IRB, IRB.CreateXor(FramePointerLong,1210IRB.CreateLShr(FramePointerLong, 20)));1211StackTag->setName("hwasan.stack.base.tag");1212return StackTag;1213}12141215Value *HWAddressSanitizer::getAllocaTag(IRBuilder<> &IRB, Value *StackTag,1216unsigned AllocaNo) {1217if (ClGenerateTagsWithCalls)1218return getNextTagWithCall(IRB);1219return IRB.CreateXor(1220StackTag, ConstantInt::get(StackTag->getType(), retagMask(AllocaNo)));1221}12221223Value *HWAddressSanitizer::getUARTag(IRBuilder<> &IRB) {1224Value *FramePointerLong = getCachedFP(IRB);1225Value *UARTag =1226applyTagMask(IRB, IRB.CreateLShr(FramePointerLong, PointerTagShift));12271228UARTag->setName("hwasan.uar.tag");1229return UARTag;1230}12311232// Add a tag to an address.1233Value *HWAddressSanitizer::tagPointer(IRBuilder<> &IRB, Type *Ty,1234Value *PtrLong, Value *Tag) {1235assert(!UsePageAliases);1236Value *TaggedPtrLong;1237if (CompileKernel) {1238// Kernel addresses have 0xFF in the most significant byte.1239Value *ShiftedTag =1240IRB.CreateOr(IRB.CreateShl(Tag, PointerTagShift),1241ConstantInt::get(IntptrTy, (1ULL << PointerTagShift) - 1));1242TaggedPtrLong = IRB.CreateAnd(PtrLong, ShiftedTag);1243} else {1244// Userspace can simply do OR (tag << PointerTagShift);1245Value *ShiftedTag = IRB.CreateShl(Tag, PointerTagShift);1246TaggedPtrLong = IRB.CreateOr(PtrLong, ShiftedTag);1247}1248return IRB.CreateIntToPtr(TaggedPtrLong, Ty);1249}12501251// Remove tag from an address.1252Value *HWAddressSanitizer::untagPointer(IRBuilder<> &IRB, Value *PtrLong) {1253assert(!UsePageAliases);1254Value *UntaggedPtrLong;1255if (CompileKernel) {1256// Kernel addresses have 0xFF in the most significant byte.1257UntaggedPtrLong =1258IRB.CreateOr(PtrLong, ConstantInt::get(PtrLong->getType(),1259TagMaskByte << PointerTagShift));1260} else {1261// Userspace addresses have 0x00.1262UntaggedPtrLong = IRB.CreateAnd(1263PtrLong, ConstantInt::get(PtrLong->getType(),1264~(TagMaskByte << PointerTagShift)));1265}1266return UntaggedPtrLong;1267}12681269Value *HWAddressSanitizer::getHwasanThreadSlotPtr(IRBuilder<> &IRB) {1270// Android provides a fixed TLS slot for sanitizers. See TLS_SLOT_SANITIZER1271// in Bionic's libc/platform/bionic/tls_defines.h.1272constexpr int SanitizerSlot = 6;1273if (TargetTriple.isAArch64() && TargetTriple.isAndroid())1274return memtag::getAndroidSlotPtr(IRB, SanitizerSlot);1275return ThreadPtrGlobal;1276}12771278Value *HWAddressSanitizer::getCachedFP(IRBuilder<> &IRB) {1279if (!CachedFP)1280CachedFP = memtag::getFP(IRB);1281return CachedFP;1282}12831284Value *HWAddressSanitizer::getFrameRecordInfo(IRBuilder<> &IRB) {1285// Prepare ring buffer data.1286Value *PC = memtag::getPC(TargetTriple, IRB);1287Value *FP = getCachedFP(IRB);12881289// Mix FP and PC.1290// Assumptions:1291// PC is 0x0000PPPPPPPPPPPP (48 bits are meaningful, others are zero)1292// FP is 0xfffffffffffFFFF0 (4 lower bits are zero)1293// We only really need ~20 lower non-zero bits (FFFF), so we mix like this:1294// 0xFFFFPPPPPPPPPPPP1295//1296// FP works because in AArch64FrameLowering::getFrameIndexReference, we1297// prefer FP-relative offsets for functions compiled with HWASan.1298FP = IRB.CreateShl(FP, 44);1299return IRB.CreateOr(PC, FP);1300}13011302void HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord) {1303if (!Mapping.InTls)1304ShadowBase = getShadowNonTls(IRB);1305else if (!WithFrameRecord && TargetTriple.isAndroid())1306ShadowBase = getDynamicShadowIfunc(IRB);13071308if (!WithFrameRecord && ShadowBase)1309return;13101311Value *SlotPtr = nullptr;1312Value *ThreadLong = nullptr;1313Value *ThreadLongMaybeUntagged = nullptr;13141315auto getThreadLongMaybeUntagged = [&]() {1316if (!SlotPtr)1317SlotPtr = getHwasanThreadSlotPtr(IRB);1318if (!ThreadLong)1319ThreadLong = IRB.CreateLoad(IntptrTy, SlotPtr);1320// Extract the address field from ThreadLong. Unnecessary on AArch64 with1321// TBI.1322return TargetTriple.isAArch64() ? ThreadLong1323: untagPointer(IRB, ThreadLong);1324};13251326if (WithFrameRecord) {1327switch (ClRecordStackHistory) {1328case libcall: {1329// Emit a runtime call into hwasan rather than emitting instructions for1330// recording stack history.1331Value *FrameRecordInfo = getFrameRecordInfo(IRB);1332IRB.CreateCall(HwasanRecordFrameRecordFunc, {FrameRecordInfo});1333break;1334}1335case instr: {1336ThreadLongMaybeUntagged = getThreadLongMaybeUntagged();13371338StackBaseTag = IRB.CreateAShr(ThreadLong, 3);13391340// Store data to ring buffer.1341Value *FrameRecordInfo = getFrameRecordInfo(IRB);1342Value *RecordPtr =1343IRB.CreateIntToPtr(ThreadLongMaybeUntagged, IRB.getPtrTy(0));1344IRB.CreateStore(FrameRecordInfo, RecordPtr);13451346// Update the ring buffer. Top byte of ThreadLong defines the size of the1347// buffer in pages, it must be a power of two, and the start of the buffer1348// must be aligned by twice that much. Therefore wrap around of the ring1349// buffer is simply Addr &= ~((ThreadLong >> 56) << 12).1350// The use of AShr instead of LShr is due to1351// https://bugs.llvm.org/show_bug.cgi?id=390301352// Runtime library makes sure not to use the highest bit.1353//1354// Mechanical proof of this address calculation can be found at:1355// https://github.com/google/sanitizers/blob/master/hwaddress-sanitizer/prove_hwasanwrap.smt21356//1357// Example of the wrap case for N = 11358// Pointer: 0x01AAAAAAAAAAAFF81359// +1360// 0x00000000000000081361// =1362// 0x01AAAAAAAAAAB0001363// &1364// WrapMask: 0xFFFFFFFFFFFFF0001365// =1366// 0x01AAAAAAAAAAA0001367//1368// Then the WrapMask will be a no-op until the next wrap case.1369Value *WrapMask = IRB.CreateXor(1370IRB.CreateShl(IRB.CreateAShr(ThreadLong, 56), 12, "", true, true),1371ConstantInt::get(IntptrTy, (uint64_t)-1));1372Value *ThreadLongNew = IRB.CreateAnd(1373IRB.CreateAdd(ThreadLong, ConstantInt::get(IntptrTy, 8)), WrapMask);1374IRB.CreateStore(ThreadLongNew, SlotPtr);1375break;1376}1377case none: {1378llvm_unreachable(1379"A stack history recording mode should've been selected.");1380}1381}1382}13831384if (!ShadowBase) {1385if (!ThreadLongMaybeUntagged)1386ThreadLongMaybeUntagged = getThreadLongMaybeUntagged();13871388// Get shadow base address by aligning RecordPtr up.1389// Note: this is not correct if the pointer is already aligned.1390// Runtime library will make sure this never happens.1391ShadowBase = IRB.CreateAdd(1392IRB.CreateOr(1393ThreadLongMaybeUntagged,1394ConstantInt::get(IntptrTy, (1ULL << kShadowBaseAlignment) - 1)),1395ConstantInt::get(IntptrTy, 1), "hwasan.shadow");1396ShadowBase = IRB.CreateIntToPtr(ShadowBase, PtrTy);1397}1398}13991400bool HWAddressSanitizer::instrumentLandingPads(1401SmallVectorImpl<Instruction *> &LandingPadVec) {1402for (auto *LP : LandingPadVec) {1403IRBuilder<> IRB(LP->getNextNonDebugInstruction());1404IRB.CreateCall(1405HwasanHandleVfork,1406{memtag::readRegister(1407IRB, (TargetTriple.getArch() == Triple::x86_64) ? "rsp" : "sp")});1408}1409return true;1410}14111412bool HWAddressSanitizer::instrumentStack(memtag::StackInfo &SInfo,1413Value *StackTag, Value *UARTag,1414const DominatorTree &DT,1415const PostDominatorTree &PDT,1416const LoopInfo &LI) {1417// Ideally, we want to calculate tagged stack base pointer, and rewrite all1418// alloca addresses using that. Unfortunately, offsets are not known yet1419// (unless we use ASan-style mega-alloca). Instead we keep the base tag in a1420// temp, shift-OR it into each alloca address and xor with the retag mask.1421// This generates one extra instruction per alloca use.1422unsigned int I = 0;14231424for (auto &KV : SInfo.AllocasToInstrument) {1425auto N = I++;1426auto *AI = KV.first;1427memtag::AllocaInfo &Info = KV.second;1428IRBuilder<> IRB(AI->getNextNonDebugInstruction());14291430// Replace uses of the alloca with tagged address.1431Value *Tag = getAllocaTag(IRB, StackTag, N);1432Value *AILong = IRB.CreatePointerCast(AI, IntptrTy);1433Value *AINoTagLong = untagPointer(IRB, AILong);1434Value *Replacement = tagPointer(IRB, AI->getType(), AINoTagLong, Tag);1435std::string Name =1436AI->hasName() ? AI->getName().str() : "alloca." + itostr(N);1437Replacement->setName(Name + ".hwasan");14381439size_t Size = memtag::getAllocaSizeInBytes(*AI);1440size_t AlignedSize = alignTo(Size, Mapping.getObjectAlignment());14411442Value *AICast = IRB.CreatePointerCast(AI, PtrTy);14431444auto HandleLifetime = [&](IntrinsicInst *II) {1445// Set the lifetime intrinsic to cover the whole alloca. This reduces the1446// set of assumptions we need to make about the lifetime. Without this we1447// would need to ensure that we can track the lifetime pointer to a1448// constant offset from the alloca, and would still need to change the1449// size to include the extra alignment we use for the untagging to make1450// the size consistent.1451//1452// The check for standard lifetime below makes sure that we have exactly1453// one set of start / end in any execution (i.e. the ends are not1454// reachable from each other), so this will not cause any problems.1455II->setArgOperand(0, ConstantInt::get(Int64Ty, AlignedSize));1456II->setArgOperand(1, AICast);1457};1458llvm::for_each(Info.LifetimeStart, HandleLifetime);1459llvm::for_each(Info.LifetimeEnd, HandleLifetime);14601461AI->replaceUsesWithIf(Replacement, [AICast, AILong](const Use &U) {1462auto *User = U.getUser();1463return User != AILong && User != AICast &&1464!memtag::isLifetimeIntrinsic(User);1465});14661467memtag::annotateDebugRecords(Info, retagMask(N));14681469auto TagEnd = [&](Instruction *Node) {1470IRB.SetInsertPoint(Node);1471// When untagging, use the `AlignedSize` because we need to set the tags1472// for the entire alloca to original. If we used `Size` here, we would1473// keep the last granule tagged, and store zero in the last byte of the1474// last granule, due to how short granules are implemented.1475tagAlloca(IRB, AI, UARTag, AlignedSize);1476};1477// Calls to functions that may return twice (e.g. setjmp) confuse the1478// postdominator analysis, and will leave us to keep memory tagged after1479// function return. Work around this by always untagging at every return1480// statement if return_twice functions are called.1481bool StandardLifetime =1482!SInfo.CallsReturnTwice &&1483SInfo.UnrecognizedLifetimes.empty() &&1484memtag::isStandardLifetime(Info.LifetimeStart, Info.LifetimeEnd, &DT,1485&LI, ClMaxLifetimes);1486if (DetectUseAfterScope && StandardLifetime) {1487IntrinsicInst *Start = Info.LifetimeStart[0];1488IRB.SetInsertPoint(Start->getNextNode());1489tagAlloca(IRB, AI, Tag, Size);1490if (!memtag::forAllReachableExits(DT, PDT, LI, Start, Info.LifetimeEnd,1491SInfo.RetVec, TagEnd)) {1492for (auto *End : Info.LifetimeEnd)1493End->eraseFromParent();1494}1495} else {1496tagAlloca(IRB, AI, Tag, Size);1497for (auto *RI : SInfo.RetVec)1498TagEnd(RI);1499// We inserted tagging outside of the lifetimes, so we have to remove1500// them.1501for (auto &II : Info.LifetimeStart)1502II->eraseFromParent();1503for (auto &II : Info.LifetimeEnd)1504II->eraseFromParent();1505}1506memtag::alignAndPadAlloca(Info, Mapping.getObjectAlignment());1507}1508for (auto &I : SInfo.UnrecognizedLifetimes)1509I->eraseFromParent();1510return true;1511}15121513static void emitRemark(const Function &F, OptimizationRemarkEmitter &ORE,1514bool Skip) {1515if (Skip) {1516ORE.emit([&]() {1517return OptimizationRemark(DEBUG_TYPE, "Skip", &F)1518<< "Skipped: F=" << ore::NV("Function", &F);1519});1520} else {1521ORE.emit([&]() {1522return OptimizationRemarkMissed(DEBUG_TYPE, "Sanitize", &F)1523<< "Sanitized: F=" << ore::NV("Function", &F);1524});1525}1526}15271528bool HWAddressSanitizer::selectiveInstrumentationShouldSkip(1529Function &F, FunctionAnalysisManager &FAM) const {1530bool Skip = [&]() {1531if (ClRandomSkipRate.getNumOccurrences()) {1532std::bernoulli_distribution D(ClRandomSkipRate);1533return !D(*Rng);1534}1535if (!ClHotPercentileCutoff.getNumOccurrences())1536return false;1537auto &MAMProxy = FAM.getResult<ModuleAnalysisManagerFunctionProxy>(F);1538ProfileSummaryInfo *PSI =1539MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent());1540if (!PSI || !PSI->hasProfileSummary()) {1541++NumNoProfileSummaryFuncs;1542return false;1543}1544return PSI->isFunctionHotInCallGraphNthPercentile(1545ClHotPercentileCutoff, &F, FAM.getResult<BlockFrequencyAnalysis>(F));1546}();1547emitRemark(F, FAM.getResult<OptimizationRemarkEmitterAnalysis>(F), Skip);1548return Skip;1549}15501551void HWAddressSanitizer::sanitizeFunction(Function &F,1552FunctionAnalysisManager &FAM) {1553if (&F == HwasanCtorFunction)1554return;15551556if (!F.hasFnAttribute(Attribute::SanitizeHWAddress))1557return;15581559if (F.empty())1560return;15611562NumTotalFuncs++;15631564OptimizationRemarkEmitter &ORE =1565FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);15661567if (selectiveInstrumentationShouldSkip(F, FAM))1568return;15691570NumInstrumentedFuncs++;15711572LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n");15731574SmallVector<InterestingMemoryOperand, 16> OperandsToInstrument;1575SmallVector<MemIntrinsic *, 16> IntrinToInstrument;1576SmallVector<Instruction *, 8> LandingPadVec;1577const TargetLibraryInfo &TLI = FAM.getResult<TargetLibraryAnalysis>(F);15781579memtag::StackInfoBuilder SIB(SSI);1580for (auto &Inst : instructions(F)) {1581if (InstrumentStack) {1582SIB.visit(Inst);1583}15841585if (InstrumentLandingPads && isa<LandingPadInst>(Inst))1586LandingPadVec.push_back(&Inst);15871588getInterestingMemoryOperands(ORE, &Inst, TLI, OperandsToInstrument);15891590if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(&Inst))1591if (!ignoreMemIntrinsic(ORE, MI))1592IntrinToInstrument.push_back(MI);1593}15941595memtag::StackInfo &SInfo = SIB.get();15961597initializeCallbacks(*F.getParent());15981599if (!LandingPadVec.empty())1600instrumentLandingPads(LandingPadVec);16011602if (SInfo.AllocasToInstrument.empty() && F.hasPersonalityFn() &&1603F.getPersonalityFn()->getName() == kHwasanPersonalityThunkName) {1604// __hwasan_personality_thunk is a no-op for functions without an1605// instrumented stack, so we can drop it.1606F.setPersonalityFn(nullptr);1607}16081609if (SInfo.AllocasToInstrument.empty() && OperandsToInstrument.empty() &&1610IntrinToInstrument.empty())1611return;16121613assert(!ShadowBase);16141615// Remove memory attributes that are about to become invalid.1616// HWASan checks read from shadow, which invalidates memory(argmem: *)1617// Short granule checks on function arguments read from the argument memory1618// (last byte of the granule), which invalidates writeonly.1619F.removeFnAttr(llvm::Attribute::Memory);1620for (auto &A : F.args())1621A.removeAttr(llvm::Attribute::WriteOnly);16221623BasicBlock::iterator InsertPt = F.getEntryBlock().begin();1624IRBuilder<> EntryIRB(&F.getEntryBlock(), InsertPt);1625emitPrologue(EntryIRB,1626/*WithFrameRecord*/ ClRecordStackHistory != none &&1627Mapping.WithFrameRecord &&1628!SInfo.AllocasToInstrument.empty());16291630if (!SInfo.AllocasToInstrument.empty()) {1631const DominatorTree &DT = FAM.getResult<DominatorTreeAnalysis>(F);1632const PostDominatorTree &PDT = FAM.getResult<PostDominatorTreeAnalysis>(F);1633const LoopInfo &LI = FAM.getResult<LoopAnalysis>(F);1634Value *StackTag = getStackBaseTag(EntryIRB);1635Value *UARTag = getUARTag(EntryIRB);1636instrumentStack(SInfo, StackTag, UARTag, DT, PDT, LI);1637}16381639// If we split the entry block, move any allocas that were originally in the1640// entry block back into the entry block so that they aren't treated as1641// dynamic allocas.1642if (EntryIRB.GetInsertBlock() != &F.getEntryBlock()) {1643InsertPt = F.getEntryBlock().begin();1644for (Instruction &I :1645llvm::make_early_inc_range(*EntryIRB.GetInsertBlock())) {1646if (auto *AI = dyn_cast<AllocaInst>(&I))1647if (isa<ConstantInt>(AI->getArraySize()))1648I.moveBefore(F.getEntryBlock(), InsertPt);1649}1650}16511652DominatorTree *DT = FAM.getCachedResult<DominatorTreeAnalysis>(F);1653PostDominatorTree *PDT = FAM.getCachedResult<PostDominatorTreeAnalysis>(F);1654LoopInfo *LI = FAM.getCachedResult<LoopAnalysis>(F);1655DomTreeUpdater DTU(DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy);1656for (auto &Operand : OperandsToInstrument)1657instrumentMemAccess(Operand, DTU, LI);1658DTU.flush();16591660if (ClInstrumentMemIntrinsics && !IntrinToInstrument.empty()) {1661for (auto *Inst : IntrinToInstrument)1662instrumentMemIntrinsic(Inst);1663}16641665ShadowBase = nullptr;1666StackBaseTag = nullptr;1667CachedFP = nullptr;1668}16691670void HWAddressSanitizer::instrumentGlobal(GlobalVariable *GV, uint8_t Tag) {1671assert(!UsePageAliases);1672Constant *Initializer = GV->getInitializer();1673uint64_t SizeInBytes =1674M.getDataLayout().getTypeAllocSize(Initializer->getType());1675uint64_t NewSize = alignTo(SizeInBytes, Mapping.getObjectAlignment());1676if (SizeInBytes != NewSize) {1677// Pad the initializer out to the next multiple of 16 bytes and add the1678// required short granule tag.1679std::vector<uint8_t> Init(NewSize - SizeInBytes, 0);1680Init.back() = Tag;1681Constant *Padding = ConstantDataArray::get(*C, Init);1682Initializer = ConstantStruct::getAnon({Initializer, Padding});1683}16841685auto *NewGV = new GlobalVariable(M, Initializer->getType(), GV->isConstant(),1686GlobalValue::ExternalLinkage, Initializer,1687GV->getName() + ".hwasan");1688NewGV->copyAttributesFrom(GV);1689NewGV->setLinkage(GlobalValue::PrivateLinkage);1690NewGV->copyMetadata(GV, 0);1691NewGV->setAlignment(1692std::max(GV->getAlign().valueOrOne(), Mapping.getObjectAlignment()));16931694// It is invalid to ICF two globals that have different tags. In the case1695// where the size of the global is a multiple of the tag granularity the1696// contents of the globals may be the same but the tags (i.e. symbol values)1697// may be different, and the symbols are not considered during ICF. In the1698// case where the size is not a multiple of the granularity, the short granule1699// tags would discriminate two globals with different tags, but there would1700// otherwise be nothing stopping such a global from being incorrectly ICF'd1701// with an uninstrumented (i.e. tag 0) global that happened to have the short1702// granule tag in the last byte.1703NewGV->setUnnamedAddr(GlobalValue::UnnamedAddr::None);17041705// Descriptor format (assuming little-endian):1706// bytes 0-3: relative address of global1707// bytes 4-6: size of global (16MB ought to be enough for anyone, but in case1708// it isn't, we create multiple descriptors)1709// byte 7: tag1710auto *DescriptorTy = StructType::get(Int32Ty, Int32Ty);1711const uint64_t MaxDescriptorSize = 0xfffff0;1712for (uint64_t DescriptorPos = 0; DescriptorPos < SizeInBytes;1713DescriptorPos += MaxDescriptorSize) {1714auto *Descriptor =1715new GlobalVariable(M, DescriptorTy, true, GlobalValue::PrivateLinkage,1716nullptr, GV->getName() + ".hwasan.descriptor");1717auto *GVRelPtr = ConstantExpr::getTrunc(1718ConstantExpr::getAdd(1719ConstantExpr::getSub(1720ConstantExpr::getPtrToInt(NewGV, Int64Ty),1721ConstantExpr::getPtrToInt(Descriptor, Int64Ty)),1722ConstantInt::get(Int64Ty, DescriptorPos)),1723Int32Ty);1724uint32_t Size = std::min(SizeInBytes - DescriptorPos, MaxDescriptorSize);1725auto *SizeAndTag = ConstantInt::get(Int32Ty, Size | (uint32_t(Tag) << 24));1726Descriptor->setComdat(NewGV->getComdat());1727Descriptor->setInitializer(ConstantStruct::getAnon({GVRelPtr, SizeAndTag}));1728Descriptor->setSection("hwasan_globals");1729Descriptor->setMetadata(LLVMContext::MD_associated,1730MDNode::get(*C, ValueAsMetadata::get(NewGV)));1731appendToCompilerUsed(M, Descriptor);1732}17331734Constant *Aliasee = ConstantExpr::getIntToPtr(1735ConstantExpr::getAdd(1736ConstantExpr::getPtrToInt(NewGV, Int64Ty),1737ConstantInt::get(Int64Ty, uint64_t(Tag) << PointerTagShift)),1738GV->getType());1739auto *Alias = GlobalAlias::create(GV->getValueType(), GV->getAddressSpace(),1740GV->getLinkage(), "", Aliasee, &M);1741Alias->setVisibility(GV->getVisibility());1742Alias->takeName(GV);1743GV->replaceAllUsesWith(Alias);1744GV->eraseFromParent();1745}17461747void HWAddressSanitizer::instrumentGlobals() {1748std::vector<GlobalVariable *> Globals;1749for (GlobalVariable &GV : M.globals()) {1750if (GV.hasSanitizerMetadata() && GV.getSanitizerMetadata().NoHWAddress)1751continue;17521753if (GV.isDeclarationForLinker() || GV.getName().starts_with("llvm.") ||1754GV.isThreadLocal())1755continue;17561757// Common symbols can't have aliases point to them, so they can't be tagged.1758if (GV.hasCommonLinkage())1759continue;17601761// Globals with custom sections may be used in __start_/__stop_ enumeration,1762// which would be broken both by adding tags and potentially by the extra1763// padding/alignment that we insert.1764if (GV.hasSection())1765continue;17661767Globals.push_back(&GV);1768}17691770MD5 Hasher;1771Hasher.update(M.getSourceFileName());1772MD5::MD5Result Hash;1773Hasher.final(Hash);1774uint8_t Tag = Hash[0];17751776assert(TagMaskByte >= 16);17771778for (GlobalVariable *GV : Globals) {1779// Don't allow globals to be tagged with something that looks like a1780// short-granule tag, otherwise we lose inter-granule overflow detection, as1781// the fast path shadow-vs-address check succeeds.1782if (Tag < 16 || Tag > TagMaskByte)1783Tag = 16;1784instrumentGlobal(GV, Tag++);1785}1786}17871788void HWAddressSanitizer::instrumentPersonalityFunctions() {1789// We need to untag stack frames as we unwind past them. That is the job of1790// the personality function wrapper, which either wraps an existing1791// personality function or acts as a personality function on its own. Each1792// function that has a personality function or that can be unwound past has1793// its personality function changed to a thunk that calls the personality1794// function wrapper in the runtime.1795MapVector<Constant *, std::vector<Function *>> PersonalityFns;1796for (Function &F : M) {1797if (F.isDeclaration() || !F.hasFnAttribute(Attribute::SanitizeHWAddress))1798continue;17991800if (F.hasPersonalityFn()) {1801PersonalityFns[F.getPersonalityFn()->stripPointerCasts()].push_back(&F);1802} else if (!F.hasFnAttribute(Attribute::NoUnwind)) {1803PersonalityFns[nullptr].push_back(&F);1804}1805}18061807if (PersonalityFns.empty())1808return;18091810FunctionCallee HwasanPersonalityWrapper = M.getOrInsertFunction(1811"__hwasan_personality_wrapper", Int32Ty, Int32Ty, Int32Ty, Int64Ty, PtrTy,1812PtrTy, PtrTy, PtrTy, PtrTy);1813FunctionCallee UnwindGetGR = M.getOrInsertFunction("_Unwind_GetGR", VoidTy);1814FunctionCallee UnwindGetCFA = M.getOrInsertFunction("_Unwind_GetCFA", VoidTy);18151816for (auto &P : PersonalityFns) {1817std::string ThunkName = kHwasanPersonalityThunkName;1818if (P.first)1819ThunkName += ("." + P.first->getName()).str();1820FunctionType *ThunkFnTy = FunctionType::get(1821Int32Ty, {Int32Ty, Int32Ty, Int64Ty, PtrTy, PtrTy}, false);1822bool IsLocal = P.first && (!isa<GlobalValue>(P.first) ||1823cast<GlobalValue>(P.first)->hasLocalLinkage());1824auto *ThunkFn = Function::Create(ThunkFnTy,1825IsLocal ? GlobalValue::InternalLinkage1826: GlobalValue::LinkOnceODRLinkage,1827ThunkName, &M);1828if (!IsLocal) {1829ThunkFn->setVisibility(GlobalValue::HiddenVisibility);1830ThunkFn->setComdat(M.getOrInsertComdat(ThunkName));1831}18321833auto *BB = BasicBlock::Create(*C, "entry", ThunkFn);1834IRBuilder<> IRB(BB);1835CallInst *WrapperCall = IRB.CreateCall(1836HwasanPersonalityWrapper,1837{ThunkFn->getArg(0), ThunkFn->getArg(1), ThunkFn->getArg(2),1838ThunkFn->getArg(3), ThunkFn->getArg(4),1839P.first ? P.first : Constant::getNullValue(PtrTy),1840UnwindGetGR.getCallee(), UnwindGetCFA.getCallee()});1841WrapperCall->setTailCall();1842IRB.CreateRet(WrapperCall);18431844for (Function *F : P.second)1845F->setPersonalityFn(ThunkFn);1846}1847}18481849void HWAddressSanitizer::ShadowMapping::init(Triple &TargetTriple,1850bool InstrumentWithCalls) {1851Scale = kDefaultShadowScale;1852if (TargetTriple.isOSFuchsia()) {1853// Fuchsia is always PIE, which means that the beginning of the address1854// space is always available.1855InGlobal = false;1856InTls = false;1857Offset = 0;1858WithFrameRecord = true;1859} else if (ClMappingOffset.getNumOccurrences() > 0) {1860InGlobal = false;1861InTls = false;1862Offset = ClMappingOffset;1863WithFrameRecord = false;1864} else if (ClEnableKhwasan || InstrumentWithCalls) {1865InGlobal = false;1866InTls = false;1867Offset = 0;1868WithFrameRecord = false;1869} else if (ClWithIfunc) {1870InGlobal = true;1871InTls = false;1872Offset = kDynamicShadowSentinel;1873WithFrameRecord = false;1874} else if (ClWithTls) {1875InGlobal = false;1876InTls = true;1877Offset = kDynamicShadowSentinel;1878WithFrameRecord = true;1879} else {1880InGlobal = false;1881InTls = false;1882Offset = kDynamicShadowSentinel;1883WithFrameRecord = false;1884}1885}188618871888