Index: include/llvm/Transforms/Utils/ASanStackFrameLayout.h =================================================================== --- include/llvm/Transforms/Utils/ASanStackFrameLayout.h +++ include/llvm/Transforms/Utils/ASanStackFrameLayout.h @@ -43,9 +43,7 @@ // Output data struct for ComputeASanStackFrameLayout. struct ASanStackFrameLayout { - size_t Granularity; - // Frame description, see DescribeAddressIfStack in ASan runtime. - SmallString<64> DescriptionString; + size_t Granularity; // Shadow granularity. size_t FrameAlignment; // Alignment for the entire frame. size_t FrameSize; // Size of the frame in bytes. }; @@ -60,6 +58,10 @@ // The resulting FrameSize should be multiple of MinHeaderSize. size_t MinHeaderSize); +// Compute frame description, see DescribeAddressIfStack in ASan runtime. +SmallString<64> ComputeASanStackFrameDescription( + const SmallVectorImpl &Vars); + // Returns shadow bytes with marked red zones. This shadow represents the state // if the stack frame when all local variables are inside of the own scope. SmallVector Index: lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -2246,26 +2246,6 @@ // If we have a call to llvm.localescape, keep it in the entry block. if (LocalEscapeCall) LocalEscapeCall->moveBefore(InsBefore); - // Find static allocas with lifetime analysis. - DenseMap> - AllocaToSVDMap; - for (const auto &APC : StaticAllocaPoisonCallVec) { - assert(APC.InsBefore); - assert(APC.AI); - assert(ASan.isInterestingAlloca(*APC.AI)); - assert(APC.AI->isStaticAlloca()); - - auto &Pair = AllocaToSVDMap[APC.AI]; - if (const DILocation *FnLoc = EntryDebugLocation.get()) { - if (const DILocation *LifetimeLoc = APC.InsBefore->getDebugLoc().get()) { - if (LifetimeLoc->getFile() == FnLoc->getFile()) - if (unsigned Line = LifetimeLoc->getLine()) - Pair.second = std::min(Pair.second ? Pair.second : Line, Line); - } - } - } - SmallVector SVD; SVD.reserve(AllocaVec.size()); for (AllocaInst *AI : AllocaVec) { @@ -2276,20 +2256,40 @@ AI, 0, 0}; - auto It = AllocaToSVDMap.find(AI); - if (It != AllocaToSVDMap.end()) { - D.LifetimeSize = D.Size; - D.Line = It->second.second; - } SVD.push_back(D); } + // Minimal header size (left redzone) is 4 pointers, // i.e. 32 bytes on 64-bit platforms and 16 bytes in 32-bit platforms. size_t MinHeaderSize = ASan.LongSize / 2; const ASanStackFrameLayout &L = ComputeASanStackFrameLayout(SVD, 1ULL << Mapping.Scale, MinHeaderSize); - DEBUG(dbgs() << L.DescriptionString << " --- " << L.FrameSize << "\n"); + // Build AllocaToSVDMap for ASanStackVariableDescription lookup. + DenseMap AllocaToSVDMap; + for (auto &Desc : SVD) + AllocaToSVDMap[Desc.AI] = &Desc; + + // Update SVD with information from lifetime intrinsics. + for (const auto &APC : StaticAllocaPoisonCallVec) { + assert(APC.InsBefore); + assert(APC.AI); + assert(ASan.isInterestingAlloca(*APC.AI)); + assert(APC.AI->isStaticAlloca()); + + ASanStackVariableDescription &Desc = *AllocaToSVDMap[APC.AI]; + Desc.LifetimeSize = Desc.Size; + if (const DILocation *FnLoc = EntryDebugLocation.get()) { + if (const DILocation *LifetimeLoc = APC.InsBefore->getDebugLoc().get()) { + if (LifetimeLoc->getFile() == FnLoc->getFile()) + if (unsigned Line = LifetimeLoc->getLine()) + Desc.Line = std::min(Desc.Line ? Desc.Line : Line, Line); + } + } + } + + auto DescriptionString = ComputeASanStackFrameDescription(SVD); + DEBUG(dbgs() << DescriptionString << " --- " << L.FrameSize << "\n"); uint64_t LocalStackSize = L.FrameSize; bool DoStackMalloc = ClUseAfterReturn && !ASan.CompileKernel && LocalStackSize <= kMaxStackMallocSize; @@ -2372,7 +2372,7 @@ ConstantInt::get(IntptrTy, ASan.LongSize / 8)), IntptrPtrTy); GlobalVariable *StackDescriptionGlobal = - createPrivateGlobalForString(*F.getParent(), L.DescriptionString, + createPrivateGlobalForString(*F.getParent(), DescriptionString, /*AllowMerging*/ true); Value *Description = IRB.CreatePointerCast(StackDescriptionGlobal, IntptrTy); IRB.CreateStore(Description, BasePlus1); @@ -2392,21 +2392,11 @@ copyToShadow(ShadowAfterScope, ShadowAfterScope, IRB, ShadowBase); if (!StaticAllocaPoisonCallVec.empty()) { - // Complete AllocaToSVDMap - for (const auto &Desc : SVD) { - auto It = AllocaToSVDMap.find(Desc.AI); - if (It != AllocaToSVDMap.end()) { - It->second.first = &Desc; - } - } - const auto &ShadowInScope = GetShadowBytes(SVD, L); // Poison static allocas near lifetime intrinsics. for (const auto &APC : StaticAllocaPoisonCallVec) { - // Must be already set. - assert(AllocaToSVDMap[APC.AI].first); - const auto &Desc = *AllocaToSVDMap[APC.AI].first; + const ASanStackVariableDescription &Desc = *AllocaToSVDMap[APC.AI]; assert(Desc.Offset % L.Granularity == 0); size_t Begin = Desc.Offset / L.Granularity; size_t End = Begin + (APC.Size + L.Granularity - 1) / L.Granularity; Index: lib/Transforms/Utils/ASanStackFrameLayout.cpp =================================================================== --- lib/Transforms/Utils/ASanStackFrameLayout.cpp +++ lib/Transforms/Utils/ASanStackFrameLayout.cpp @@ -61,9 +61,6 @@ Vars[i].Alignment = std::max(Vars[i].Alignment, kMinAlignment); std::stable_sort(Vars.begin(), Vars.end(), CompareVars); - SmallString<2048> StackDescriptionStorage; - raw_svector_ostream StackDescription(StackDescriptionStorage); - StackDescription << NumVars; ASanStackFrameLayout Layout; Layout.Granularity = Granularity; @@ -76,34 +73,42 @@ size_t Alignment = std::max(Granularity, Vars[i].Alignment); (void)Alignment; // Used only in asserts. size_t Size = Vars[i].Size; - std::string Name = Vars[i].Name; assert((Alignment & (Alignment - 1)) == 0); assert(Layout.FrameAlignment >= Alignment); assert((Offset % Alignment) == 0); assert(Size > 0); - assert(Vars[i].LifetimeSize <= Size); - if (Vars[i].Line) { - Name += ":"; - Name += std::to_string(Vars[i].Line); - } - StackDescription << " " << Offset << " " << Size << " " << Name.size() - << " " << Name; size_t NextAlignment = IsLast ? Granularity : std::max(Granularity, Vars[i + 1].Alignment); - size_t SizeWithRedzone = VarAndRedzoneSize(Vars[i].Size, NextAlignment); + size_t SizeWithRedzone = VarAndRedzoneSize(Size, NextAlignment); Vars[i].Offset = Offset; Offset += SizeWithRedzone; } if (Offset % MinHeaderSize) { Offset += MinHeaderSize - (Offset % MinHeaderSize); } - Layout.DescriptionString = StackDescription.str(); Layout.FrameSize = Offset; assert((Layout.FrameSize % MinHeaderSize) == 0); - return Layout; } +SmallString<64> ComputeASanStackFrameDescription( + const SmallVectorImpl &Vars) { + SmallString<2048> StackDescriptionStorage; + raw_svector_ostream StackDescription(StackDescriptionStorage); + StackDescription << Vars.size(); + + for (const auto &Var : Vars) { + std::string Name = Var.Name; + if (Var.Line) { + Name += ":"; + Name += std::to_string(Var.Line); + } + StackDescription << " " << Var.Offset << " " << Var.Size << " " + << Name.size() << " " << Name; + } + return StackDescription.str(); +} + SmallVector GetShadowBytes(const SmallVectorImpl &Vars, const ASanStackFrameLayout &Layout) { @@ -130,6 +135,7 @@ const size_t Granularity = Layout.Granularity; for (const auto &Var : Vars) { + assert(Var.LifetimeSize <= Var.Size); const size_t LifetimeShadowSize = (Var.LifetimeSize + Granularity - 1) / Granularity; const size_t Offset = Var.Offset / Granularity; Index: unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp =================================================================== --- unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp +++ unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp @@ -37,7 +37,8 @@ SmallVector Vars = V; \ ASanStackFrameLayout L = \ ComputeASanStackFrameLayout(Vars, Granularity, MinHeaderSize); \ - EXPECT_STREQ(ExpectedDescr, L.DescriptionString.c_str()); \ + EXPECT_STREQ(ExpectedDescr, \ + ComputeASanStackFrameDescription(Vars).c_str()); \ EXPECT_EQ(ExpectedShadow, ShadowBytesToString(GetShadowBytes(Vars, L))); \ EXPECT_EQ(ExpectedShadowAfterScope, \ ShadowBytesToString(GetShadowBytesAfterScope(Vars, L))); \