Index: lib/CodeGen/SafeStack.cpp =================================================================== --- lib/CodeGen/SafeStack.cpp +++ lib/CodeGen/SafeStack.cpp @@ -606,16 +606,39 @@ StaticOffset += Size; StaticOffset = alignTo(StaticOffset, Align); - Value *Off = IRB.CreateGEP(BasePointer, // BasePointer is i8* - ConstantInt::get(Int32Ty, -StaticOffset)); - Value *NewAI = IRB.CreateBitCast(Off, AI->getType(), AI->getName()); - if (AI->hasName() && isa(NewAI)) - cast(NewAI)->takeName(AI); - - // Replace alloc with the new location. replaceDbgDeclareForAlloca(AI, BasePointer, DIB, /*Deref=*/true, -StaticOffset); replaceDbgValueForAlloca(AI, BasePointer, DIB, -StaticOffset); - AI->replaceAllUsesWith(NewAI); + + // Replace uses of the alloca with the new location. + // Insert address calculation close to each use. + std::string Name = std::string(AI->getName()) + ".unsafe"; + while (!AI->use_empty()) { + Use &U = *AI->use_begin(); + Instruction *User = cast(U.getUser()); + + Instruction *InsertBefore; + if (auto *PHI = dyn_cast(User)) + InsertBefore = PHI->getIncomingBlock(U)->getTerminator(); + else + InsertBefore = User; + + IRBuilder<> IRBUser(InsertBefore); + Value *Off = IRBUser.CreateGEP(BasePointer, // BasePointer is i8* + ConstantInt::get(Int32Ty, -StaticOffset)); + Value *Replacement = IRBUser.CreateBitCast(Off, AI->getType(), Name); + + if (auto *PHI = dyn_cast(User)) { + // PHI nodes may have multiple incoming edges from the same BB (why??), + // all must be updated at once with the same incoming value. + auto *BB = PHI->getIncomingBlock(U); + for (unsigned I = 0; I < PHI->getNumIncomingValues(); ++I) + if (PHI->getIncomingBlock(I) == BB) + PHI->setIncomingValue(I, Replacement); + } else { + U.set(Replacement); + } + } + AI->eraseFromParent(); } Index: test/Transforms/SafeStack/array-aligned.ll =================================================================== --- test/Transforms/SafeStack/array-aligned.ll +++ test/Transforms/SafeStack/array-aligned.ll @@ -13,16 +13,15 @@ ; CHECK: store i8* %[[USST]], i8** @__safestack_unsafe_stack_ptr - ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8 %a.addr = alloca i8*, align 8 - - ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -16 - ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to [16 x i8]* %buf = alloca [16 x i8], align 16 + ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8 ; CHECK: store i8* {{.*}}, i8** %[[AADDR]], align 8 store i8* %a, i8** %a.addr, align 8 + ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -16 + ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to [16 x i8]* ; CHECK: %[[GEP:.*]] = getelementptr inbounds [16 x i8], [16 x i8]* %[[BUFPTR2]], i32 0, i32 0 %gep = getelementptr inbounds [16 x i8], [16 x i8]* %buf, i32 0, i32 0 Index: test/Transforms/SafeStack/array.ll =================================================================== --- test/Transforms/SafeStack/array.ll +++ test/Transforms/SafeStack/array.ll @@ -17,16 +17,15 @@ ; CHECK: store i8* %[[USST]], i8** @__safestack_unsafe_stack_ptr - ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8 %a.addr = alloca i8*, align 8 - - ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -4 - ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to [4 x i8]* %buf = alloca [4 x i8], align 1 + ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8 ; CHECK: store i8* {{.*}}, i8** %[[AADDR]], align 8 store i8* %a, i8** %a.addr, align 8 + ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -4 + ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to [4 x i8]* ; CHECK: %[[GEP:.*]] = getelementptr inbounds [4 x i8], [4 x i8]* %[[BUFPTR2]], i32 0, i32 0 %gep = getelementptr inbounds [4 x i8], [4 x i8]* %buf, i32 0, i32 0 Index: test/Transforms/SafeStack/sink-to-use.ll =================================================================== --- /dev/null +++ test/Transforms/SafeStack/sink-to-use.ll @@ -0,0 +1,22 @@ +; Test that unsafe alloca address calculation is done immediately before each use. +; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s +; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s + +define void @f() safestack { +entry: + %x0 = alloca i32, align 4 + %x1 = alloca i32, align 4 + +; CHECK: %[[A:.*]] = getelementptr i8, i8* %{{.*}}, i32 -4 +; CHECK: %[[X0:.*]] = bitcast i8* %[[A]] to i32* +; CHECK: call void @use(i32* %[[X0]]) + call void @use(i32* %x0) + +; CHECK: %[[B:.*]] = getelementptr i8, i8* %{{.*}}, i32 -8 +; CHECK: %[[X1:.*]] = bitcast i8* %[[B]] to i32* +; CHECK: call void @use(i32* %[[X1]]) + call void @use(i32* %x1) + ret void +} + +declare void @use(i32*) Index: test/Transforms/SafeStack/struct.ll =================================================================== --- test/Transforms/SafeStack/struct.ll +++ test/Transforms/SafeStack/struct.ll @@ -15,16 +15,15 @@ ; CHECK: store i8* %[[USST]], i8** @__safestack_unsafe_stack_ptr - ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8 %a.addr = alloca i8*, align 8 - - ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -16 - ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to %struct.foo* %buf = alloca %struct.foo, align 1 + ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8 ; CHECK: store i8* {{.*}}, i8** %[[AADDR]], align 8 store i8* %a, i8** %a.addr, align 8 + ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -16 + ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to %struct.foo* ; CHECK: %[[GEP:.*]] = getelementptr inbounds %struct.foo, %struct.foo* %[[BUFPTR2]], i32 0, i32 0, i32 0 %gep = getelementptr inbounds %struct.foo, %struct.foo* %buf, i32 0, i32 0, i32 0