diff options
Diffstat (limited to 'lib/Transforms/Instrumentation/SanitizerCoverage.cpp')
| -rw-r--r-- | lib/Transforms/Instrumentation/SanitizerCoverage.cpp | 260 | 
1 files changed, 211 insertions, 49 deletions
| diff --git a/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/lib/Transforms/Instrumentation/SanitizerCoverage.cpp index 06fe07598374..d950e2e730f2 100644 --- a/lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ b/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -17,12 +17,16 @@  #include "llvm/Analysis/PostDominators.h"  #include "llvm/IR/CFG.h"  #include "llvm/IR/CallSite.h" +#include "llvm/IR/Constant.h"  #include "llvm/IR/DataLayout.h"  #include "llvm/IR/DebugInfo.h"  #include "llvm/IR/Dominators.h"  #include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h"  #include "llvm/IR/IRBuilder.h"  #include "llvm/IR/InlineAsm.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h"  #include "llvm/IR/LLVMContext.h"  #include "llvm/IR/MDBuilder.h"  #include "llvm/IR/Module.h" @@ -46,6 +50,14 @@ static const char *const SanCovTraceCmp1 = "__sanitizer_cov_trace_cmp1";  static const char *const SanCovTraceCmp2 = "__sanitizer_cov_trace_cmp2";  static const char *const SanCovTraceCmp4 = "__sanitizer_cov_trace_cmp4";  static const char *const SanCovTraceCmp8 = "__sanitizer_cov_trace_cmp8"; +static const char *const SanCovTraceConstCmp1 = +    "__sanitizer_cov_trace_const_cmp1"; +static const char *const SanCovTraceConstCmp2 = +    "__sanitizer_cov_trace_const_cmp2"; +static const char *const SanCovTraceConstCmp4 = +    "__sanitizer_cov_trace_const_cmp4"; +static const char *const SanCovTraceConstCmp8 = +    "__sanitizer_cov_trace_const_cmp8";  static const char *const SanCovTraceDiv4 = "__sanitizer_cov_trace_div4";  static const char *const SanCovTraceDiv8 = "__sanitizer_cov_trace_div8";  static const char *const SanCovTraceGep = "__sanitizer_cov_trace_gep"; @@ -57,11 +69,15 @@ static const char *const SanCovTracePCGuardName =      "__sanitizer_cov_trace_pc_guard";  static const char *const SanCovTracePCGuardInitName =      "__sanitizer_cov_trace_pc_guard_init"; -static const char *const SanCov8bitCountersInitName =  +static const char *const SanCov8bitCountersInitName =      "__sanitizer_cov_8bit_counters_init"; +static const char *const SanCovPCsInitName = "__sanitizer_cov_pcs_init";  static const char *const SanCovGuardsSectionName = "sancov_guards";  static const char *const SanCovCountersSectionName = "sancov_cntrs"; +static const char *const SanCovPCsSectionName = "sancov_pcs"; + +static const char *const SanCovLowestStackName = "__sancov_lowest_stack";  static cl::opt<int> ClCoverageLevel(      "sanitizer-coverage-level", @@ -77,9 +93,19 @@ static cl::opt<bool> ClTracePCGuard("sanitizer-coverage-trace-pc-guard",                                      cl::desc("pc tracing with a guard"),                                      cl::Hidden, cl::init(false)); -static cl::opt<bool> ClInline8bitCounters("sanitizer-coverage-inline-8bit-counters", -                                    cl::desc("increments 8-bit counter for every edge"), -                                    cl::Hidden, cl::init(false)); +// If true, we create a global variable that contains PCs of all instrumented +// BBs, put this global into a named section, and pass this section's bounds +// to __sanitizer_cov_pcs_init. +// This way the coverage instrumentation does not need to acquire the PCs +// at run-time. Works with trace-pc-guard and inline-8bit-counters. +static cl::opt<bool> ClCreatePCTable("sanitizer-coverage-pc-table", +                                     cl::desc("create a static PC table"), +                                     cl::Hidden, cl::init(false)); + +static cl::opt<bool> +    ClInline8bitCounters("sanitizer-coverage-inline-8bit-counters", +                         cl::desc("increments 8-bit counter for every edge"), +                         cl::Hidden, cl::init(false));  static cl::opt<bool>      ClCMPTracing("sanitizer-coverage-trace-compares", @@ -99,6 +125,10 @@ static cl::opt<bool>                    cl::desc("Reduce the number of instrumented blocks"),                    cl::Hidden, cl::init(true)); +static cl::opt<bool> ClStackDepth("sanitizer-coverage-stack-depth", +                                  cl::desc("max stack depth tracing"), +                                  cl::Hidden, cl::init(false)); +  namespace {  SanitizerCoverageOptions getOptions(int LegacyCoverageLevel) { @@ -135,9 +165,12 @@ SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) {    Options.TracePC |= ClTracePC;    Options.TracePCGuard |= ClTracePCGuard;    Options.Inline8bitCounters |= ClInline8bitCounters; -  if (!Options.TracePCGuard && !Options.TracePC && !Options.Inline8bitCounters) -    Options.TracePCGuard = true; // TracePCGuard is default. +  Options.PCTable |= ClCreatePCTable;    Options.NoPrune |= !ClPruneBlocks; +  Options.StackDepth |= ClStackDepth; +  if (!Options.TracePCGuard && !Options.TracePC && +      !Options.Inline8bitCounters && !Options.StackDepth) +    Options.TracePCGuard = true; // TracePCGuard is default.    return Options;  } @@ -168,14 +201,19 @@ private:                           ArrayRef<GetElementPtrInst *> GepTraceTargets);    void InjectTraceForSwitch(Function &F,                              ArrayRef<Instruction *> SwitchTraceTargets); -  bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks); +  bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks, +                      bool IsLeafFunc = true);    GlobalVariable *CreateFunctionLocalArrayInSection(size_t NumElements,                                                      Function &F, Type *Ty,                                                      const char *Section); -  void CreateFunctionLocalArrays(size_t NumGuards, Function &F); -  void InjectCoverageAtBlock(Function &F, BasicBlock &BB, size_t Idx); -  void CreateInitCallForSection(Module &M, const char *InitFunctionName, -                                Type *Ty, const std::string &Section); +  GlobalVariable *CreatePCArray(Function &F, ArrayRef<BasicBlock *> AllBlocks); +  void CreateFunctionLocalArrays(Function &F, ArrayRef<BasicBlock *> AllBlocks); +  void InjectCoverageAtBlock(Function &F, BasicBlock &BB, size_t Idx, +                             bool IsLeafFunc = true); +  Function *CreateInitCallsForSections(Module &M, const char *InitFunctionName, +                                       Type *Ty, const char *Section); +  std::pair<GlobalVariable *, GlobalVariable *> +  CreateSecStartEnd(Module &M, const char *Section, Type *Ty);    void SetNoSanitizeMetadata(Instruction *I) {      I->setMetadata(I->getModule()->getMDKindID("nosanitize"), @@ -188,12 +226,14 @@ private:    Function *SanCovTracePCIndir;    Function *SanCovTracePC, *SanCovTracePCGuard;    Function *SanCovTraceCmpFunction[4]; +  Function *SanCovTraceConstCmpFunction[4];    Function *SanCovTraceDivFunction[2];    Function *SanCovTraceGepFunction;    Function *SanCovTraceSwitchFunction; +  GlobalVariable *SanCovLowestStack;    InlineAsm *EmptyAsm;    Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy, -      *Int8Ty, *Int8PtrTy; +      *Int16Ty, *Int8Ty, *Int8PtrTy;    Module *CurModule;    Triple TargetTriple;    LLVMContext *C; @@ -201,17 +241,17 @@ private:    GlobalVariable *FunctionGuardArray;  // for trace-pc-guard.    GlobalVariable *Function8bitCounterArray;  // for inline-8bit-counters. +  GlobalVariable *FunctionPCsArray;  // for pc-table. +  SmallVector<GlobalValue *, 20> GlobalsToAppendToUsed;    SanitizerCoverageOptions Options;  };  } // namespace -void SanitizerCoverageModule::CreateInitCallForSection( -    Module &M, const char *InitFunctionName, Type *Ty, -    const std::string &Section) { -  IRBuilder<> IRB(M.getContext()); -  Function *CtorFunc; +std::pair<GlobalVariable *, GlobalVariable *> +SanitizerCoverageModule::CreateSecStartEnd(Module &M, const char *Section, +                                           Type *Ty) {    GlobalVariable *SecStart =        new GlobalVariable(M, Ty, false, GlobalVariable::ExternalLinkage, nullptr,                           getSectionStart(Section)); @@ -221,6 +261,18 @@ void SanitizerCoverageModule::CreateInitCallForSection(                           nullptr, getSectionEnd(Section));    SecEnd->setVisibility(GlobalValue::HiddenVisibility); +  return std::make_pair(SecStart, SecEnd); +} + + +Function *SanitizerCoverageModule::CreateInitCallsForSections( +    Module &M, const char *InitFunctionName, Type *Ty, +    const char *Section) { +  IRBuilder<> IRB(M.getContext()); +  auto SecStartEnd = CreateSecStartEnd(M, Section, Ty); +  auto SecStart = SecStartEnd.first; +  auto SecEnd = SecStartEnd.second; +  Function *CtorFunc;    std::tie(CtorFunc, std::ignore) = createSanitizerCtorAndInitFunctions(        M, SanCovModuleCtorName, InitFunctionName, {Ty, Ty},        {IRB.CreatePointerCast(SecStart, Ty), IRB.CreatePointerCast(SecEnd, Ty)}); @@ -232,6 +284,7 @@ void SanitizerCoverageModule::CreateInitCallForSection(    } else {      appendToGlobalCtors(M, CtorFunc, SanCtorAndDtorPriority);    } +  return CtorFunc;  }  bool SanitizerCoverageModule::runOnModule(Module &M) { @@ -243,6 +296,7 @@ bool SanitizerCoverageModule::runOnModule(Module &M) {    TargetTriple = Triple(M.getTargetTriple());    FunctionGuardArray = nullptr;    Function8bitCounterArray = nullptr; +  FunctionPCsArray = nullptr;    IntptrTy = Type::getIntNTy(*C, DL->getPointerSizeInBits());    IntptrPtrTy = PointerType::getUnqual(IntptrTy);    Type *VoidTy = Type::getVoidTy(*C); @@ -252,6 +306,7 @@ bool SanitizerCoverageModule::runOnModule(Module &M) {    Int8PtrTy = PointerType::getUnqual(IRB.getInt8Ty());    Int64Ty = IRB.getInt64Ty();    Int32Ty = IRB.getInt32Ty(); +  Int16Ty = IRB.getInt16Ty();    Int8Ty = IRB.getInt8Ty();    SanCovTracePCIndir = checkSanitizerInterfaceFunction( @@ -269,6 +324,19 @@ bool SanitizerCoverageModule::runOnModule(Module &M) {        checkSanitizerInterfaceFunction(M.getOrInsertFunction(            SanCovTraceCmp8, VoidTy, Int64Ty, Int64Ty)); +  SanCovTraceConstCmpFunction[0] = +      checkSanitizerInterfaceFunction(M.getOrInsertFunction( +          SanCovTraceConstCmp1, VoidTy, Int8Ty, Int8Ty)); +  SanCovTraceConstCmpFunction[1] = +      checkSanitizerInterfaceFunction(M.getOrInsertFunction( +          SanCovTraceConstCmp2, VoidTy, Int16Ty, Int16Ty)); +  SanCovTraceConstCmpFunction[2] = +      checkSanitizerInterfaceFunction(M.getOrInsertFunction( +          SanCovTraceConstCmp4, VoidTy, Int32Ty, Int32Ty)); +  SanCovTraceConstCmpFunction[3] = +      checkSanitizerInterfaceFunction(M.getOrInsertFunction( +          SanCovTraceConstCmp8, VoidTy, Int64Ty, Int64Ty)); +    SanCovTraceDivFunction[0] =        checkSanitizerInterfaceFunction(M.getOrInsertFunction(            SanCovTraceDiv4, VoidTy, IRB.getInt32Ty())); @@ -281,12 +349,23 @@ bool SanitizerCoverageModule::runOnModule(Module &M) {    SanCovTraceSwitchFunction =        checkSanitizerInterfaceFunction(M.getOrInsertFunction(            SanCovTraceSwitchName, VoidTy, Int64Ty, Int64PtrTy)); + +  Constant *SanCovLowestStackConstant = +      M.getOrInsertGlobal(SanCovLowestStackName, IntptrTy); +  SanCovLowestStack = cast<GlobalVariable>(SanCovLowestStackConstant); +  SanCovLowestStack->setThreadLocalMode( +      GlobalValue::ThreadLocalMode::InitialExecTLSModel); +  if (Options.StackDepth && !SanCovLowestStack->isDeclaration()) +    SanCovLowestStack->setInitializer(Constant::getAllOnesValue(IntptrTy)); +    // Make sure smaller parameters are zero-extended to i64 as required by the    // x86_64 ABI.    if (TargetTriple.getArch() == Triple::x86_64) {      for (int i = 0; i < 3; i++) {        SanCovTraceCmpFunction[i]->addParamAttr(0, Attribute::ZExt);        SanCovTraceCmpFunction[i]->addParamAttr(1, Attribute::ZExt); +      SanCovTraceConstCmpFunction[i]->addParamAttr(0, Attribute::ZExt); +      SanCovTraceConstCmpFunction[i]->addParamAttr(1, Attribute::ZExt);      }      SanCovTraceDivFunction[0]->addParamAttr(0, Attribute::ZExt);    } @@ -305,13 +384,27 @@ bool SanitizerCoverageModule::runOnModule(Module &M) {    for (auto &F : M)      runOnFunction(F); +  Function *Ctor = nullptr; +    if (FunctionGuardArray) -    CreateInitCallForSection(M, SanCovTracePCGuardInitName, Int32PtrTy, -                             SanCovGuardsSectionName); +    Ctor = CreateInitCallsForSections(M, SanCovTracePCGuardInitName, Int32PtrTy, +                                      SanCovGuardsSectionName);    if (Function8bitCounterArray) -    CreateInitCallForSection(M, SanCov8bitCountersInitName, Int8PtrTy, -                             SanCovCountersSectionName); - +    Ctor = CreateInitCallsForSections(M, SanCov8bitCountersInitName, Int8PtrTy, +                                      SanCovCountersSectionName); +  if (Ctor && Options.PCTable) { +    auto SecStartEnd = CreateSecStartEnd(M, SanCovPCsSectionName, IntptrPtrTy); +    Function *InitFunction = declareSanitizerInitFunction( +        M, SanCovPCsInitName, {IntptrPtrTy, IntptrPtrTy}); +    IRBuilder<> IRBCtor(Ctor->getEntryBlock().getTerminator()); +    IRBCtor.CreateCall(InitFunction, +                       {IRB.CreatePointerCast(SecStartEnd.first, IntptrPtrTy), +                        IRB.CreatePointerCast(SecStartEnd.second, IntptrPtrTy)}); +  } +  // We don't reference these arrays directly in any of our runtime functions, +  // so we need to prevent them from being dead stripped. +  if (TargetTriple.isOSBinFormatMachO()) +    appendToUsed(M, GlobalsToAppendToUsed);    return true;  } @@ -362,6 +455,10 @@ static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,    if (Options.NoPrune || &F.getEntryBlock() == BB)      return true; +  if (Options.CoverageType == SanitizerCoverageOptions::SCK_Function && +      &F.getEntryBlock() != BB) +    return false; +    // Do not instrument full dominators, or full post-dominators with multiple    // predecessors.    return !isFullDominator(BB, DT) @@ -375,6 +472,9 @@ bool SanitizerCoverageModule::runOnFunction(Function &F) {      return false; // Should not instrument sanitizer init functions.    if (F.getName().startswith("__sanitizer_"))      return false;  // Don't instrument __sanitizer_* callbacks. +  // Don't touch available_externally functions, their actual body is elewhere. +  if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) +    return false;    // Don't instrument MSVC CRT configuration helpers. They may run before normal    // initialization.    if (F.getName() == "__local_stdio_printf_options" || @@ -399,6 +499,7 @@ bool SanitizerCoverageModule::runOnFunction(Function &F) {        &getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();    const PostDominatorTree *PDT =        &getAnalysis<PostDominatorTreeWrapperPass>(F).getPostDomTree(); +  bool IsLeafFunc = true;    for (auto &BB : F) {      if (shouldInstrumentBlock(F, &BB, DT, PDT, Options)) @@ -423,10 +524,14 @@ bool SanitizerCoverageModule::runOnFunction(Function &F) {        if (Options.TraceGep)          if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(&Inst))            GepTraceTargets.push_back(GEP); -   } +      if (Options.StackDepth) +        if (isa<InvokeInst>(Inst) || +            (isa<CallInst>(Inst) && !isa<IntrinsicInst>(Inst))) +          IsLeafFunc = false; +    }    } -  InjectCoverage(F, BlocksToInstrument); +  InjectCoverage(F, BlocksToInstrument, IsLeafFunc);    InjectCoverageForIndirectCalls(F, IndirCalls);    InjectTraceForCmp(F, CmpTraceTargets);    InjectTraceForSwitch(F, SwitchTraceTargets); @@ -444,35 +549,65 @@ GlobalVariable *SanitizerCoverageModule::CreateFunctionLocalArrayInSection(    if (auto Comdat = F.getComdat())      Array->setComdat(Comdat);    Array->setSection(getSectionName(Section)); +  Array->setAlignment(Ty->isPointerTy() ? DL->getPointerSize() +                                        : Ty->getPrimitiveSizeInBits() / 8);    return Array;  } -void SanitizerCoverageModule::CreateFunctionLocalArrays(size_t NumGuards, -                                                       Function &F) { -  if (Options.TracePCGuard) + +GlobalVariable * +SanitizerCoverageModule::CreatePCArray(Function &F, +                                       ArrayRef<BasicBlock *> AllBlocks) { +  size_t N = AllBlocks.size(); +  assert(N); +  SmallVector<Constant *, 32> PCs; +  IRBuilder<> IRB(&*F.getEntryBlock().getFirstInsertionPt()); +  for (size_t i = 0; i < N; i++) { +    if (&F.getEntryBlock() == AllBlocks[i]) { +      PCs.push_back((Constant *)IRB.CreatePointerCast(&F, IntptrPtrTy)); +      PCs.push_back((Constant *)IRB.CreateIntToPtr( +          ConstantInt::get(IntptrTy, 1), IntptrPtrTy)); +    } else { +      PCs.push_back((Constant *)IRB.CreatePointerCast( +          BlockAddress::get(AllBlocks[i]), IntptrPtrTy)); +      PCs.push_back((Constant *)IRB.CreateIntToPtr( +          ConstantInt::get(IntptrTy, 0), IntptrPtrTy)); +    } +  } +  auto *PCArray = CreateFunctionLocalArrayInSection(N * 2, F, IntptrPtrTy, +                                                    SanCovPCsSectionName); +  PCArray->setInitializer( +      ConstantArray::get(ArrayType::get(IntptrPtrTy, N * 2), PCs)); +  PCArray->setConstant(true); + +  return PCArray; +} + +void SanitizerCoverageModule::CreateFunctionLocalArrays( +    Function &F, ArrayRef<BasicBlock *> AllBlocks) { +  if (Options.TracePCGuard) {      FunctionGuardArray = CreateFunctionLocalArrayInSection( -        NumGuards, F, Int32Ty, SanCovGuardsSectionName); -  if (Options.Inline8bitCounters) +        AllBlocks.size(), F, Int32Ty, SanCovGuardsSectionName); +    GlobalsToAppendToUsed.push_back(FunctionGuardArray); +  } +  if (Options.Inline8bitCounters) {      Function8bitCounterArray = CreateFunctionLocalArrayInSection( -        NumGuards, F, Int8Ty, SanCovCountersSectionName); +        AllBlocks.size(), F, Int8Ty, SanCovCountersSectionName); +    GlobalsToAppendToUsed.push_back(Function8bitCounterArray); +  } +  if (Options.PCTable) { +    FunctionPCsArray = CreatePCArray(F, AllBlocks); +    GlobalsToAppendToUsed.push_back(FunctionPCsArray); +  }  }  bool SanitizerCoverageModule::InjectCoverage(Function &F, -                                             ArrayRef<BasicBlock *> AllBlocks) { +                                             ArrayRef<BasicBlock *> AllBlocks, +                                             bool IsLeafFunc) {    if (AllBlocks.empty()) return false; -  switch (Options.CoverageType) { -  case SanitizerCoverageOptions::SCK_None: -    return false; -  case SanitizerCoverageOptions::SCK_Function: -    CreateFunctionLocalArrays(1, F); -    InjectCoverageAtBlock(F, F.getEntryBlock(), 0); -    return true; -  default: { -    CreateFunctionLocalArrays(AllBlocks.size(), F); -    for (size_t i = 0, N = AllBlocks.size(); i < N; i++) -      InjectCoverageAtBlock(F, *AllBlocks[i], i); -    return true; -  } -  } +  CreateFunctionLocalArrays(F, AllBlocks); +  for (size_t i = 0, N = AllBlocks.size(); i < N; i++) +    InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc); +  return true;  }  // On every indirect call we call a run-time function @@ -585,16 +720,28 @@ void SanitizerCoverageModule::InjectTraceForCmp(                          TypeSize == 64 ? 3 : -1;        if (CallbackIdx < 0) continue;        // __sanitizer_cov_trace_cmp((type_size << 32) | predicate, A0, A1); +      auto CallbackFunc = SanCovTraceCmpFunction[CallbackIdx]; +      bool FirstIsConst = isa<ConstantInt>(A0); +      bool SecondIsConst = isa<ConstantInt>(A1); +      // If both are const, then we don't need such a comparison. +      if (FirstIsConst && SecondIsConst) continue; +      // If only one is const, then make it the first callback argument. +      if (FirstIsConst || SecondIsConst) { +        CallbackFunc = SanCovTraceConstCmpFunction[CallbackIdx]; +        if (SecondIsConst) +          std::swap(A0, A1); +      } +        auto Ty = Type::getIntNTy(*C, TypeSize); -      IRB.CreateCall( -          SanCovTraceCmpFunction[CallbackIdx], -          {IRB.CreateIntCast(A0, Ty, true), IRB.CreateIntCast(A1, Ty, true)}); +      IRB.CreateCall(CallbackFunc, {IRB.CreateIntCast(A0, Ty, true), +              IRB.CreateIntCast(A1, Ty, true)});      }    }  }  void SanitizerCoverageModule::InjectCoverageAtBlock(Function &F, BasicBlock &BB, -                                                    size_t Idx) { +                                                    size_t Idx, +                                                    bool IsLeafFunc) {    BasicBlock::iterator IP = BB.getFirstInsertionPt();    bool IsEntryBB = &BB == &F.getEntryBlock();    DebugLoc EntryLoc; @@ -633,6 +780,21 @@ void SanitizerCoverageModule::InjectCoverageAtBlock(Function &F, BasicBlock &BB,      SetNoSanitizeMetadata(Load);      SetNoSanitizeMetadata(Store);    } +  if (Options.StackDepth && IsEntryBB && !IsLeafFunc) { +    // Check stack depth.  If it's the deepest so far, record it. +    Function *GetFrameAddr = +        Intrinsic::getDeclaration(F.getParent(), Intrinsic::frameaddress); +    auto FrameAddrPtr = +        IRB.CreateCall(GetFrameAddr, {Constant::getNullValue(Int32Ty)}); +    auto FrameAddrInt = IRB.CreatePtrToInt(FrameAddrPtr, IntptrTy); +    auto LowestStack = IRB.CreateLoad(SanCovLowestStack); +    auto IsStackLower = IRB.CreateICmpULT(FrameAddrInt, LowestStack); +    auto ThenTerm = SplitBlockAndInsertIfThen(IsStackLower, &*IP, false); +    IRBuilder<> ThenIRB(ThenTerm); +    auto Store = ThenIRB.CreateStore(FrameAddrInt, SanCovLowestStack); +    SetNoSanitizeMetadata(LowestStack); +    SetNoSanitizeMetadata(Store); +  }  }  std::string | 
