Index: lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -1649,180 +1649,185 @@ for (auto &AllocaCall : DynamicAllocaVec) handleDynamicAllocaCall(AllocaCall); - if (AllocaVec.size() == 0) return; + if (AllocaVec.size() > 0) { + int StackMallocIdx = -1; + DebugLoc EntryDebugLocation = getFunctionEntryDebugLocation(F); - int StackMallocIdx = -1; - DebugLoc EntryDebugLocation = getFunctionEntryDebugLocation(F); - - Instruction *InsBefore = AllocaVec[0]; - IRBuilder<> IRB(InsBefore); - IRB.SetCurrentDebugLocation(EntryDebugLocation); - - SmallVector SVD; - SVD.reserve(AllocaVec.size()); - for (AllocaInst *AI : AllocaVec) { - ASanStackVariableDescription D = { AI->getName().data(), - getAllocaSizeInBytes(AI), - AI->getAlignment(), AI, 0}; - 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; - ASanStackFrameLayout L; - ComputeASanStackFrameLayout(SVD, 1UL << Mapping.Scale, MinHeaderSize, &L); - DEBUG(dbgs() << L.DescriptionString << " --- " << L.FrameSize << "\n"); - uint64_t LocalStackSize = L.FrameSize; - bool DoStackMalloc = - ClUseAfterReturn && LocalStackSize <= kMaxStackMallocSize; - // Don't do dynamic alloca in presence of inline asm: too often it - // makes assumptions on which registers are available. - bool DoDynamicAlloca = ClDynamicAllocaStack && !HasNonEmptyInlineAsm; - - Value *StaticAlloca = - DoDynamicAlloca ? nullptr : createAllocaForLayout(IRB, L, false); - - Value *FakeStack; - Value *LocalStackBase; - - if (DoStackMalloc) { - // void *FakeStack = __asan_option_detect_stack_use_after_return - // ? __asan_stack_malloc_N(LocalStackSize) - // : nullptr; - // void *LocalStackBase = (FakeStack) ? FakeStack : alloca(LocalStackSize); - Constant *OptionDetectUAR = F.getParent()->getOrInsertGlobal( - kAsanOptionDetectUAR, IRB.getInt32Ty()); - Value *UARIsEnabled = - IRB.CreateICmpNE(IRB.CreateLoad(OptionDetectUAR), - Constant::getNullValue(IRB.getInt32Ty())); - Instruction *Term = - SplitBlockAndInsertIfThen(UARIsEnabled, InsBefore, false); - IRBuilder<> IRBIf(Term); - IRBIf.SetCurrentDebugLocation(EntryDebugLocation); - StackMallocIdx = StackMallocSizeClass(LocalStackSize); - assert(StackMallocIdx <= kMaxAsanStackMallocSizeClass); - Value *FakeStackValue = - IRBIf.CreateCall(AsanStackMallocFunc[StackMallocIdx], - ConstantInt::get(IntptrTy, LocalStackSize)); - IRB.SetInsertPoint(InsBefore); + Instruction *InsBefore = AllocaVec[0]; + IRBuilder<> IRB(InsBefore); IRB.SetCurrentDebugLocation(EntryDebugLocation); - FakeStack = createPHI(IRB, UARIsEnabled, FakeStackValue, Term, - ConstantInt::get(IntptrTy, 0)); - Value *NoFakeStack = - IRB.CreateICmpEQ(FakeStack, Constant::getNullValue(IntptrTy)); - Term = SplitBlockAndInsertIfThen(NoFakeStack, InsBefore, false); - IRBIf.SetInsertPoint(Term); - IRBIf.SetCurrentDebugLocation(EntryDebugLocation); - Value *AllocaValue = - DoDynamicAlloca ? createAllocaForLayout(IRBIf, L, true) : StaticAlloca; - IRB.SetInsertPoint(InsBefore); - IRB.SetCurrentDebugLocation(EntryDebugLocation); - LocalStackBase = createPHI(IRB, NoFakeStack, AllocaValue, Term, FakeStack); - } else { - // void *FakeStack = nullptr; - // void *LocalStackBase = alloca(LocalStackSize); - FakeStack = ConstantInt::get(IntptrTy, 0); - LocalStackBase = - DoDynamicAlloca ? createAllocaForLayout(IRB, L, true) : StaticAlloca; - } - - // Insert poison calls for lifetime intrinsics for alloca. - bool HavePoisonedAllocas = false; - for (const auto &APC : AllocaPoisonCallVec) { - assert(APC.InsBefore); - assert(APC.AI); - IRBuilder<> IRB(APC.InsBefore); - poisonAlloca(APC.AI, APC.Size, IRB, APC.DoPoison); - HavePoisonedAllocas |= APC.DoPoison; - } - - // Replace Alloca instructions with base+offset. - for (const auto &Desc : SVD) { - AllocaInst *AI = Desc.AI; - Value *NewAllocaPtr = IRB.CreateIntToPtr( - IRB.CreateAdd(LocalStackBase, ConstantInt::get(IntptrTy, Desc.Offset)), - AI->getType()); - replaceDbgDeclareForAlloca(AI, NewAllocaPtr, DIB, /*Deref=*/true); - AI->replaceAllUsesWith(NewAllocaPtr); - } - - // The left-most redzone has enough space for at least 4 pointers. - // Write the Magic value to redzone[0]. - Value *BasePlus0 = IRB.CreateIntToPtr(LocalStackBase, IntptrPtrTy); - IRB.CreateStore(ConstantInt::get(IntptrTy, kCurrentStackFrameMagic), - BasePlus0); - // Write the frame description constant to redzone[1]. - Value *BasePlus1 = IRB.CreateIntToPtr( - IRB.CreateAdd(LocalStackBase, ConstantInt::get(IntptrTy, ASan.LongSize/8)), - IntptrPtrTy); - GlobalVariable *StackDescriptionGlobal = - createPrivateGlobalForString(*F.getParent(), L.DescriptionString, - /*AllowMerging*/true); - Value *Description = IRB.CreatePointerCast(StackDescriptionGlobal, - IntptrTy); - IRB.CreateStore(Description, BasePlus1); - // Write the PC to redzone[2]. - Value *BasePlus2 = IRB.CreateIntToPtr( - IRB.CreateAdd(LocalStackBase, ConstantInt::get(IntptrTy, - 2 * ASan.LongSize/8)), - IntptrPtrTy); - IRB.CreateStore(IRB.CreatePointerCast(&F, IntptrTy), BasePlus2); - - // Poison the stack redzones at the entry. - Value *ShadowBase = ASan.memToShadow(LocalStackBase, IRB); - poisonRedZones(L.ShadowBytes, IRB, ShadowBase, true); - - // (Un)poison the stack before all ret instructions. - for (auto Ret : RetVec) { - IRBuilder<> IRBRet(Ret); - // Mark the current frame as retired. - IRBRet.CreateStore(ConstantInt::get(IntptrTy, kRetiredStackFrameMagic), - BasePlus0); + SmallVector SVD; + SVD.reserve(AllocaVec.size()); + for (AllocaInst *AI : AllocaVec) { + ASanStackVariableDescription D = {AI->getName().data(), + getAllocaSizeInBytes(AI), + AI->getAlignment(), AI, 0}; + 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; + ASanStackFrameLayout L; + ComputeASanStackFrameLayout(SVD, 1UL << Mapping.Scale, MinHeaderSize, &L); + DEBUG(dbgs() << L.DescriptionString << " --- " << L.FrameSize << "\n"); + uint64_t LocalStackSize = L.FrameSize; + bool DoStackMalloc = + ClUseAfterReturn && LocalStackSize <= kMaxStackMallocSize; + // Don't do dynamic alloca in presence of inline asm: too often it + // makes assumptions on which registers are available. + bool DoDynamicAlloca = ClDynamicAllocaStack && !HasNonEmptyInlineAsm; + + Value *StaticAlloca = + DoDynamicAlloca ? nullptr : createAllocaForLayout(IRB, L, false); + + Value *FakeStack; + Value *LocalStackBase; + if (DoStackMalloc) { - assert(StackMallocIdx >= 0); - // if FakeStack != 0 // LocalStackBase == FakeStack - // // In use-after-return mode, poison the whole stack frame. - // if StackMallocIdx <= 4 - // // For small sizes inline the whole thing: - // memset(ShadowBase, kAsanStackAfterReturnMagic, ShadowSize); - // **SavedFlagPtr(FakeStack) = 0 - // else - // __asan_stack_free_N(FakeStack, LocalStackSize) - // else - // - Value *Cmp = - IRBRet.CreateICmpNE(FakeStack, Constant::getNullValue(IntptrTy)); - TerminatorInst *ThenTerm, *ElseTerm; - SplitBlockAndInsertIfThenElse(Cmp, Ret, &ThenTerm, &ElseTerm); - - IRBuilder<> IRBPoison(ThenTerm); - if (StackMallocIdx <= 4) { - int ClassSize = kMinStackMallocSize << StackMallocIdx; - SetShadowToStackAfterReturnInlined(IRBPoison, ShadowBase, - ClassSize >> Mapping.Scale); - Value *SavedFlagPtrPtr = IRBPoison.CreateAdd( - FakeStack, - ConstantInt::get(IntptrTy, ClassSize - ASan.LongSize / 8)); - Value *SavedFlagPtr = IRBPoison.CreateLoad( - IRBPoison.CreateIntToPtr(SavedFlagPtrPtr, IntptrPtrTy)); - IRBPoison.CreateStore( - Constant::getNullValue(IRBPoison.getInt8Ty()), - IRBPoison.CreateIntToPtr(SavedFlagPtr, IRBPoison.getInt8PtrTy())); + // void *FakeStack = __asan_option_detect_stack_use_after_return + // ? __asan_stack_malloc_N(LocalStackSize) + // : nullptr; + // void *LocalStackBase = (FakeStack) ? FakeStack : + // alloca(LocalStackSize); + Constant *OptionDetectUAR = F.getParent()->getOrInsertGlobal( + kAsanOptionDetectUAR, IRB.getInt32Ty()); + Value *UARIsEnabled = + IRB.CreateICmpNE(IRB.CreateLoad(OptionDetectUAR), + Constant::getNullValue(IRB.getInt32Ty())); + Instruction *Term = + SplitBlockAndInsertIfThen(UARIsEnabled, InsBefore, false); + IRBuilder<> IRBIf(Term); + IRBIf.SetCurrentDebugLocation(EntryDebugLocation); + StackMallocIdx = StackMallocSizeClass(LocalStackSize); + assert(StackMallocIdx <= kMaxAsanStackMallocSizeClass); + Value *FakeStackValue = + IRBIf.CreateCall(AsanStackMallocFunc[StackMallocIdx], + ConstantInt::get(IntptrTy, LocalStackSize)); + IRB.SetInsertPoint(InsBefore); + IRB.SetCurrentDebugLocation(EntryDebugLocation); + FakeStack = createPHI(IRB, UARIsEnabled, FakeStackValue, Term, + ConstantInt::get(IntptrTy, 0)); + + Value *NoFakeStack = + IRB.CreateICmpEQ(FakeStack, Constant::getNullValue(IntptrTy)); + Term = SplitBlockAndInsertIfThen(NoFakeStack, InsBefore, false); + IRBIf.SetInsertPoint(Term); + IRBIf.SetCurrentDebugLocation(EntryDebugLocation); + Value *AllocaValue = DoDynamicAlloca + ? createAllocaForLayout(IRBIf, L, true) + : StaticAlloca; + IRB.SetInsertPoint(InsBefore); + IRB.SetCurrentDebugLocation(EntryDebugLocation); + LocalStackBase = + createPHI(IRB, NoFakeStack, AllocaValue, Term, FakeStack); + } else { + // void *FakeStack = nullptr; + // void *LocalStackBase = alloca(LocalStackSize); + FakeStack = ConstantInt::get(IntptrTy, 0); + LocalStackBase = + DoDynamicAlloca ? createAllocaForLayout(IRB, L, true) : StaticAlloca; + } + + // Insert poison calls for lifetime intrinsics for alloca. + bool HavePoisonedAllocas = false; + for (const auto &APC : AllocaPoisonCallVec) { + assert(APC.InsBefore); + assert(APC.AI); + IRBuilder<> IRB(APC.InsBefore); + poisonAlloca(APC.AI, APC.Size, IRB, APC.DoPoison); + HavePoisonedAllocas |= APC.DoPoison; + } + + // Replace Alloca instructions with base+offset. + for (const auto &Desc : SVD) { + AllocaInst *AI = Desc.AI; + Value *NewAllocaPtr = IRB.CreateIntToPtr( + IRB.CreateAdd(LocalStackBase, + ConstantInt::get(IntptrTy, Desc.Offset)), + AI->getType()); + replaceDbgDeclareForAlloca(AI, NewAllocaPtr, DIB, /*Deref=*/true); + AI->replaceAllUsesWith(NewAllocaPtr); + } + + // The left-most redzone has enough space for at least 4 pointers. + // Write the Magic value to redzone[0]. + Value *BasePlus0 = IRB.CreateIntToPtr(LocalStackBase, IntptrPtrTy); + IRB.CreateStore(ConstantInt::get(IntptrTy, kCurrentStackFrameMagic), + BasePlus0); + // Write the frame description constant to redzone[1]. + Value *BasePlus1 = IRB.CreateIntToPtr( + IRB.CreateAdd(LocalStackBase, + ConstantInt::get(IntptrTy, ASan.LongSize / 8)), + IntptrPtrTy); + GlobalVariable *StackDescriptionGlobal = + createPrivateGlobalForString(*F.getParent(), L.DescriptionString, + /*AllowMerging*/ true); + Value *Description = + IRB.CreatePointerCast(StackDescriptionGlobal, IntptrTy); + IRB.CreateStore(Description, BasePlus1); + // Write the PC to redzone[2]. + Value *BasePlus2 = IRB.CreateIntToPtr( + IRB.CreateAdd(LocalStackBase, + ConstantInt::get(IntptrTy, 2 * ASan.LongSize / 8)), + IntptrPtrTy); + IRB.CreateStore(IRB.CreatePointerCast(&F, IntptrTy), BasePlus2); + + // Poison the stack redzones at the entry. + Value *ShadowBase = ASan.memToShadow(LocalStackBase, IRB); + poisonRedZones(L.ShadowBytes, IRB, ShadowBase, true); + + // (Un)poison the stack before all ret instructions. + for (auto Ret : RetVec) { + IRBuilder<> IRBRet(Ret); + // Mark the current frame as retired. + IRBRet.CreateStore(ConstantInt::get(IntptrTy, kRetiredStackFrameMagic), + BasePlus0); + if (DoStackMalloc) { + assert(StackMallocIdx >= 0); + // if FakeStack != 0 // LocalStackBase == FakeStack + // // In use-after-return mode, poison the whole stack frame. + // if StackMallocIdx <= 4 + // // For small sizes inline the whole thing: + // memset(ShadowBase, kAsanStackAfterReturnMagic, ShadowSize); + // **SavedFlagPtr(FakeStack) = 0 + // else + // __asan_stack_free_N(FakeStack, LocalStackSize) + // else + // + Value *Cmp = + IRBRet.CreateICmpNE(FakeStack, Constant::getNullValue(IntptrTy)); + TerminatorInst *ThenTerm, *ElseTerm; + SplitBlockAndInsertIfThenElse(Cmp, Ret, &ThenTerm, &ElseTerm); + + IRBuilder<> IRBPoison(ThenTerm); + if (StackMallocIdx <= 4) { + int ClassSize = kMinStackMallocSize << StackMallocIdx; + SetShadowToStackAfterReturnInlined(IRBPoison, ShadowBase, + ClassSize >> Mapping.Scale); + Value *SavedFlagPtrPtr = IRBPoison.CreateAdd( + FakeStack, + ConstantInt::get(IntptrTy, ClassSize - ASan.LongSize / 8)); + Value *SavedFlagPtr = IRBPoison.CreateLoad( + IRBPoison.CreateIntToPtr(SavedFlagPtrPtr, IntptrPtrTy)); + IRBPoison.CreateStore( + Constant::getNullValue(IRBPoison.getInt8Ty()), + IRBPoison.CreateIntToPtr(SavedFlagPtr, IRBPoison.getInt8PtrTy())); + } else { + // For larger frames call __asan_stack_free_*. + IRBPoison.CreateCall2(AsanStackFreeFunc[StackMallocIdx], FakeStack, + ConstantInt::get(IntptrTy, LocalStackSize)); + } + + IRBuilder<> IRBElse(ElseTerm); + poisonRedZones(L.ShadowBytes, IRBElse, ShadowBase, false); + } else if (HavePoisonedAllocas) { + // If we poisoned some allocas in llvm.lifetime analysis, + // unpoison whole stack frame now. + poisonAlloca(LocalStackBase, LocalStackSize, IRBRet, false); } else { - // For larger frames call __asan_stack_free_*. - IRBPoison.CreateCall2(AsanStackFreeFunc[StackMallocIdx], FakeStack, - ConstantInt::get(IntptrTy, LocalStackSize)); + poisonRedZones(L.ShadowBytes, IRBRet, ShadowBase, false); } - - IRBuilder<> IRBElse(ElseTerm); - poisonRedZones(L.ShadowBytes, IRBElse, ShadowBase, false); - } else if (HavePoisonedAllocas) { - // If we poisoned some allocas in llvm.lifetime analysis, - // unpoison whole stack frame now. - poisonAlloca(LocalStackBase, LocalStackSize, IRBRet, false); - } else { - poisonRedZones(L.ShadowBytes, IRBRet, ShadowBase, false); } } Index: projects/compiler-rt/test/asan/TestCases/alloca_instruments_all_paddings.cc =================================================================== --- projects/compiler-rt/test/asan/TestCases/alloca_instruments_all_paddings.cc +++ projects/compiler-rt/test/asan/TestCases/alloca_instruments_all_paddings.cc @@ -1,4 +1,5 @@ // RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t +// RUN: %clangxx_asan -O3 -mllvm -asan-instrument-allocas %s -o %t // RUN: %run %t 2>&1 //