Index: lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -629,6 +629,7 @@ void SetShadowToStackAfterReturnInlined(IRBuilder<> &IRB, Value *ShadowBase, int Size); + Value *createDynamicAlloca(IRBuilder<> &IRB, const ASanStackFrameLayout &L); }; } // namespace @@ -1545,6 +1546,18 @@ return DebugLoc(); } +Value * +FunctionStackPoisoner::createDynamicAlloca(IRBuilder<> &IRB, + const ASanStackFrameLayout &L) { + AllocaInst *DynamicAlloca = IRB.CreateAlloca( + IRB.getInt8Ty(), ConstantInt::get(IRB.getInt64Ty(), L.FrameSize), + "MyAlloca"); + assert((ClRealignStack & (ClRealignStack - 1)) == 0); + size_t FrameAlignment = std::max(L.FrameAlignment, (size_t)ClRealignStack); + DynamicAlloca->setAlignment(FrameAlignment); + return IRB.CreatePointerCast(DynamicAlloca, IntptrTy); +} + void FunctionStackPoisoner::poisonStack() { assert(AllocaVec.size() > 0 || DynamicAllocaVec.size() > 0); @@ -1579,22 +1592,19 @@ uint64_t LocalStackSize = L.FrameSize; bool DoStackMalloc = ClUseAfterReturn && LocalStackSize <= kMaxStackMallocSize; + Value *SP = nullptr; - Type *ByteArrayTy = ArrayType::get(IRB.getInt8Ty(), LocalStackSize); - AllocaInst *MyAlloca = - new AllocaInst(ByteArrayTy, "MyAlloca", InsBefore); - MyAlloca->setDebugLoc(EntryDebugLocation); - assert((ClRealignStack & (ClRealignStack - 1)) == 0); - size_t FrameAlignment = std::max(L.FrameAlignment, (size_t)ClRealignStack); - MyAlloca->setAlignment(FrameAlignment); - assert(MyAlloca->isStaticAlloca()); - Value *OrigStackBase = IRB.CreatePointerCast(MyAlloca, IntptrTy); - Value *LocalStackBase = OrigStackBase; - + Value *FakeStack; if (DoStackMalloc) { - // LocalStackBase = OrigStackBase + // void *FakeStack = nullptr; + // int8_t sp; // if (__asan_option_detect_stack_use_after_return) - // LocalStackBase = __asan_stack_malloc_N(LocalStackBase, OrigStackBase); + // FakeStack = __asan_stack_malloc_N(LocalStackSize, &sp); + AllocaInst *SPAlloca = new AllocaInst(IRB.getInt8Ty(), "sp", InsBefore); + SPAlloca->setDebugLoc(EntryDebugLocation); + assert(SPAlloca->isStaticAlloca()); + SP = IRB.CreatePointerCast(SPAlloca, IntptrTy); + StackMallocIdx = StackMallocSizeClass(LocalStackSize); assert(StackMallocIdx <= kMaxAsanStackMallocSizeClass); Constant *OptionDetectUAR = F.getParent()->getOrInsertGlobal( @@ -1602,19 +1612,46 @@ Value *Cmp = IRB.CreateICmpNE(IRB.CreateLoad(OptionDetectUAR), Constant::getNullValue(IRB.getInt32Ty())); Instruction *Term = SplitBlockAndInsertIfThen(Cmp, InsBefore, false); + + IRBuilder<> IRBIf(Term); + IRBIf.SetCurrentDebugLocation(EntryDebugLocation); + Value *FakeStackValue = + IRBIf.CreateCall2(AsanStackMallocFunc[StackMallocIdx], + ConstantInt::get(IntptrTy, LocalStackSize), SP); + + IRB.SetInsertPoint(InsBefore); + IRB.SetCurrentDebugLocation(EntryDebugLocation); + PHINode *PHI = IRB.CreatePHI(IntptrTy, 2); BasicBlock *CmpBlock = cast(Cmp)->getParent(); + PHI->addIncoming(ConstantInt::get(IntptrTy, 0), CmpBlock); + BasicBlock *SetBlock = cast(FakeStackValue)->getParent(); + PHI->addIncoming(FakeStackValue, SetBlock); + FakeStack = PHI; + } else { + // void *FakeStack = nullptr; + FakeStack = ConstantInt::get(IntptrTy, 0); + } + + // void *LocalStackBase = (FakeStack) ? FakeStack : alloca(LocalStackSize); + Value *LocalStackBase; + if (DoStackMalloc) { + Value *Cmp = IRB.CreateICmpEQ(FakeStack, Constant::getNullValue(IntptrTy)); + Instruction *Term = SplitBlockAndInsertIfThen(Cmp, InsBefore, false); + IRBuilder<> IRBIf(Term); IRBIf.SetCurrentDebugLocation(EntryDebugLocation); - LocalStackBase = IRBIf.CreateCall2( - AsanStackMallocFunc[StackMallocIdx], - ConstantInt::get(IntptrTy, LocalStackSize), OrigStackBase); - BasicBlock *SetBlock = cast(LocalStackBase)->getParent(); + Value *DynamicAllocaValue = createDynamicAlloca(IRBIf, L); + IRB.SetInsertPoint(InsBefore); IRB.SetCurrentDebugLocation(EntryDebugLocation); - PHINode *Phi = IRB.CreatePHI(IntptrTy, 2); - Phi->addIncoming(OrigStackBase, CmpBlock); - Phi->addIncoming(LocalStackBase, SetBlock); - LocalStackBase = Phi; + PHINode *PHI = IRB.CreatePHI(IntptrTy, 2); + BasicBlock *CmpBlock = cast(Cmp)->getParent(); + PHI->addIncoming(FakeStack, CmpBlock); + BasicBlock *SetBlock = cast(DynamicAllocaValue)->getParent(); + PHI->addIncoming(DynamicAllocaValue, SetBlock); + LocalStackBase = PHI; + } else { + LocalStackBase = createDynamicAlloca(IRB, L); } // Insert poison calls for lifetime intrinsics for alloca. @@ -1671,17 +1708,17 @@ BasePlus0); if (DoStackMalloc) { assert(StackMallocIdx >= 0); - // if LocalStackBase != OrigStackBase: + // if 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(LocalStackBase) = 0 // else - // __asan_stack_free_N(LocalStackBase, OrigStackBase) + // __asan_stack_free_N(LocalStackBase, unused_SP) // else // - Value *Cmp = IRBRet.CreateICmpNE(LocalStackBase, OrigStackBase); + Value *Cmp = IRBRet.CreateICmpEQ(LocalStackBase, FakeStack); TerminatorInst *ThenTerm, *ElseTerm; SplitBlockAndInsertIfThenElse(Cmp, Ret, &ThenTerm, &ElseTerm); @@ -1701,8 +1738,7 @@ } else { // For larger frames call __asan_stack_free_*. IRBPoison.CreateCall3(AsanStackFreeFunc[StackMallocIdx], LocalStackBase, - ConstantInt::get(IntptrTy, LocalStackSize), - OrigStackBase); + ConstantInt::get(IntptrTy, LocalStackSize), SP); } IRBuilder<> IRBElse(ElseTerm); @@ -1710,7 +1746,6 @@ } else if (HavePoisonedAllocas) { // If we poisoned some allocas in llvm.lifetime analysis, // unpoison whole stack frame now. - assert(LocalStackBase == OrigStackBase); poisonAlloca(LocalStackBase, LocalStackSize, IRBRet, false); } else { poisonRedZones(L.ShadowBytes, IRBRet, ShadowBase, false); Index: projects/compiler-rt/lib/asan/asan_fake_stack.cc =================================================================== --- projects/compiler-rt/lib/asan/asan_fake_stack.cc +++ projects/compiler-rt/lib/asan/asan_fake_stack.cc @@ -194,18 +194,16 @@ ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size, uptr real_stack) { FakeStack *fs = GetFakeStackFast(); - if (!fs) return real_stack; + if (!fs) return 0; FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, real_stack); - if (!ff) - return real_stack; // Out of fake stack, return the real one. + if (!ff) return 0; // Out of fake stack, return the real one. uptr ptr = reinterpret_cast(ff); SetShadow(ptr, size, class_id, 0); return ptr; } ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size, uptr real_stack) { - if (ptr == real_stack) - return; + (void)real_stack; FakeStack::Deallocate(ptr, class_id); SetShadow(ptr, size, class_id, kMagic8); }