diff options
-rw-r--r-- | docs/LangRef.rst | 17 | ||||
-rw-r--r-- | lib/CodeGen/StackProtector.cpp | 126 | ||||
-rw-r--r-- | test/CodeGen/X86/stack-protector.ll | 2530 |
3 files changed, 2635 insertions, 38 deletions
diff --git a/docs/LangRef.rst b/docs/LangRef.rst index 1a85469550..4fd4c3ee27 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -825,7 +825,11 @@ example: placed on the stack before the local variables that's checked upon return from the function to see if it has been overwritten. A heuristic is used to determine if a function needs stack protectors - or not. + or not. The heuristic used will enable protectors for functions with: + - Character arrays larger than ``ssp-buffer-size`` (default 8). + - Aggregates containing character arrays larger than ``ssp-buffer-size``. + - Calls to alloca() with variable sizes or constant sizes greater than + ``ssp-buffer-size``. If a function that has an ``ssp`` attribute is inlined into a function that doesn't have an ``ssp`` attribute, then the resulting @@ -841,8 +845,15 @@ example: an ``sspreq`` attribute. ``sspstrong`` This attribute indicates that the function should emit a stack smashing - protector. Currently this attribute has the same effect as - ``sspreq``. This overrides the ``ssp`` function attribute. + protector. This attribute causes a strong heuristic to be used when + determining if a function needs stack protectors. The strong heuristic + will enable protectors for functions with: + - Arrays of any size and type + - Aggregates containing an array of any size and type. + - Calls to alloca(). + - Local variables that have had their address taken. + + This overrides the ``ssp`` function attribute. If a function that has an ``sspstrong`` attribute is inlined into a function that doesn't have an ``sspstrong`` attribute, then the diff --git a/lib/CodeGen/StackProtector.cpp b/lib/CodeGen/StackProtector.cpp index 049efc1c86..f3be37c9ee 100644 --- a/lib/CodeGen/StackProtector.cpp +++ b/lib/CodeGen/StackProtector.cpp @@ -16,6 +16,8 @@ #define DEBUG_TYPE "stack-protector" #include "llvm/CodeGen/Passes.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/Statistic.h" #include "llvm/ADT/Triple.h" #include "llvm/Analysis/Dominators.h" #include "llvm/IR/Attributes.h" @@ -32,6 +34,10 @@ #include "llvm/Target/TargetOptions.h" using namespace llvm; +STATISTIC(NumFunProtected, "Number of functions protected"); +STATISTIC(NumAddrTaken, "Number of local variables that have their address" + " taken."); + namespace { class StackProtector : public FunctionPass { /// TLI - Keep a pointer of a TargetLowering to consult for determining @@ -43,6 +49,12 @@ namespace { DominatorTree *DT; + /// VisitedPHIs - The set of PHI nodes visited when determining + /// if a variable's reference has been taken. This set + /// is maintained to ensure we don't visit the same PHI node multiple + /// times. + SmallPtrSet<const PHINode*, 16> VisitedPHIs; + /// InsertStackProtectors - Insert code into the prologue and epilogue of /// the function. /// @@ -58,11 +70,15 @@ namespace { /// ContainsProtectableArray - Check whether the type either is an array or /// contains an array of sufficient size so that we need stack protectors /// for it. - bool ContainsProtectableArray(Type *Ty, bool InStruct = false) const; + bool ContainsProtectableArray(Type *Ty, bool Strong = false, + bool InStruct = false) const; + + /// \brief Check whether a stack allocation has its address taken. + bool HasAddressTaken(const Instruction *AI); /// RequiresStackProtector - Check whether or not this function needs a /// stack protector based upon the stack protector level. - bool RequiresStackProtector() const; + bool RequiresStackProtector(); public: static char ID; // Pass identification, replacement for typeid. StackProtector() : FunctionPass(ID), TLI(0) { @@ -96,15 +112,21 @@ bool StackProtector::runOnFunction(Function &Fn) { if (!RequiresStackProtector()) return false; + ++NumFunProtected; return InsertStackProtectors(); } /// ContainsProtectableArray - Check whether the type either is an array or /// contains a char array of sufficient size so that we need stack protectors /// for it. -bool StackProtector::ContainsProtectableArray(Type *Ty, bool InStruct) const { +bool StackProtector::ContainsProtectableArray(Type *Ty, bool Strong, + bool InStruct) const { if (!Ty) return false; if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) { + // In strong mode any array, regardless of type and size, triggers a + // protector + if (Strong) + return true; const TargetMachine &TM = TLI->getTargetMachine(); if (!AT->getElementType()->isIntegerTy(8)) { Triple Trip(TM.getTargetTriple()); @@ -126,45 +148,103 @@ bool StackProtector::ContainsProtectableArray(Type *Ty, bool InStruct) const { for (StructType::element_iterator I = ST->element_begin(), E = ST->element_end(); I != E; ++I) - if (ContainsProtectableArray(*I, true)) + if (ContainsProtectableArray(*I, Strong, true)) return true; return false; } -/// RequiresStackProtector - Check whether or not this function needs a stack -/// protector based upon the stack protector level. The heuristic we use is to -/// add a guard variable to functions that call alloca, and functions with -/// buffers larger than SSPBufferSize bytes. -bool StackProtector::RequiresStackProtector() const { - if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex, - Attribute::StackProtectReq)) - return true; +bool StackProtector::HasAddressTaken(const Instruction *AI) { + for (Value::const_use_iterator UI = AI->use_begin(), UE = AI->use_end(); + UI != UE; ++UI) { + const User *U = *UI; + if (const StoreInst *SI = dyn_cast<StoreInst>(U)) { + if (AI == SI->getValueOperand()) + return true; + } else if (const PtrToIntInst *SI = dyn_cast<PtrToIntInst>(U)) { + if (AI == SI->getOperand(0)) + return true; + } else if (isa<CallInst>(U)) { + return true; + } else if (isa<InvokeInst>(U)) { + return true; + } else if (const SelectInst *SI = dyn_cast<SelectInst>(U)) { + if (HasAddressTaken(SI)) + return true; + } else if (const PHINode *PN = dyn_cast<PHINode>(U)) { + // Keep track of what PHI nodes we have already visited to ensure + // they are only visited once. + if (VisitedPHIs.insert(PN)) + if (HasAddressTaken(PN)) + return true; + } else if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(U)) { + if (HasAddressTaken(GEP)) + return true; + } else if (const BitCastInst *BI = dyn_cast<BitCastInst>(U)) { + if (HasAddressTaken(BI)) + return true; + } + } + return false; +} - // FIXME: Dummy SSP-strong implementation. Default to required until - // strong heuristic is implemented. +/// \brief Check whether or not this function needs a stack protector based +/// upon the stack protector level. +/// +/// We use two heuristics: a standard (ssp) and strong (sspstrong). +/// The standard heuristic which will add a guard variable to functions that +/// call alloca with a either a variable size or a size >= SSPBufferSize, +/// functions with character buffers larger than SSPBufferSize, and functions +/// with aggregates containing character buffers larger than SSPBufferSize. The +/// strong heuristic will add a guard variables to functions that call alloca +/// regardless of size, functions with any buffer regardless of type and size, +/// functions with aggregates that contain any buffer regardless of type and +/// size, and functions that contain stack-based variables that have had their +/// address taken. +bool StackProtector::RequiresStackProtector() { + bool Strong = false; if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex, - Attribute::StackProtectStrong)) + Attribute::StackProtectReq)) return true; - - if (!F->getAttributes().hasAttribute(AttributeSet::FunctionIndex, - Attribute::StackProtect)) + else if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex, + Attribute::StackProtectStrong)) + Strong = true; + else if (!F->getAttributes().hasAttribute(AttributeSet::FunctionIndex, + Attribute::StackProtect)) return false; for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) { BasicBlock *BB = I; for (BasicBlock::iterator - II = BB->begin(), IE = BB->end(); II != IE; ++II) + II = BB->begin(), IE = BB->end(); II != IE; ++II) { if (AllocaInst *AI = dyn_cast<AllocaInst>(II)) { - if (AI->isArrayAllocation()) - // This is a call to alloca with a variable size. Emit stack - // protectors. + if (AI->isArrayAllocation()) { + // SSP-Strong: Enable protectors for any call to alloca, regardless + // of size. + if (Strong) + return true; + + if (const ConstantInt *CI = + dyn_cast<ConstantInt>(AI->getArraySize())) { + unsigned BufferSize = TLI->getTargetMachine().Options.SSPBufferSize; + if (CI->getLimitedValue(BufferSize) >= BufferSize) + // A call to alloca with size >= SSPBufferSize requires + // stack protectors. + return true; + } else // A call to alloca with a variable size requires protectors. + return true; + } + + if (ContainsProtectableArray(AI->getAllocatedType(), Strong)) return true; - if (ContainsProtectableArray(AI->getAllocatedType())) + if (Strong && HasAddressTaken(AI)) { + ++NumAddrTaken; return true; + } } + } } return false; diff --git a/test/CodeGen/X86/stack-protector.ll b/test/CodeGen/X86/stack-protector.ll index afe5ab81bc..1e9ca1d2c2 100644 --- a/test/CodeGen/X86/stack-protector.ll +++ b/test/CodeGen/X86/stack-protector.ll @@ -2,10 +2,19 @@ ; RUN: llc -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck --check-prefix=LINUX-X64 %s ; RUN: llc -code-model=kernel -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck --check-prefix=LINUX-KERNEL-X64 %s ; RUN: llc -mtriple=x86_64-apple-darwin < %s -o - | FileCheck --check-prefix=DARWIN-X64 %s -; FIXME: Update and expand test when strong heuristic is implemented. %struct.foo = type { [16 x i8] } %struct.foo.0 = type { [4 x i8] } +%struct.pair = type { i32, i32 } +%struct.nest = type { %struct.pair, %struct.pair } +%struct.vec = type { <4 x i32> } +%class.A = type { [2 x i8] } +%struct.deep = type { %union.anon } +%union.anon = type { %struct.anon } +%struct.anon = type { %struct.anon.0 } +%struct.anon.0 = type { %union.anon.1 } +%union.anon.1 = type { [2 x i8] } +%struct.small = type { i8 } @.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 @@ -577,26 +586,24 @@ entry: ; test5c: no arrays / no nested arrays ; sspstrong attribute -; Requires protector. -; FIXME: Once strong heuristic is implemented, this should _not_ require -; a protector +; Requires no protector. define void @test5c(i8* %a) nounwind uwtable sspstrong { entry: ; LINUX-I386: test5c: -; LINUX-I386: mov{{l|q}} %gs: -; LINUX-I386: calll __stack_chk_fail +; LINUX-I386-NOT: calll __stack_chk_fail +; LINUX-I386: .cfi_endproc ; LINUX-X64: test5c: -; LINUX-X64: mov{{l|q}} %fs: -; LINUX-X64: callq __stack_chk_fail +; LINUX-X64-NOT: callq __stack_chk_fail +; LINUX-X64: .cfi_endproc ; LINUX-KERNEL-X64: test5c: -; LINUX-KERNEL-X64: mov{{l|q}} %gs: -; LINUX-KERNEL-X64: callq __stack_chk_fail +; LINUX-KERNEL-X64-NOT: callq __stack_chk_fail +; LINUX-KERNEL-X64: .cfi_endproc ; DARWIN-X64: test5c: -; DARWIN-X64: mov{{l|q}} ___stack_chk_guard -; DARWIN-X64: callq ___stack_chk_fail +; DARWIN-X64-NOT: callq ___stack_chk_fail +; DARWIN-X64: .cfi_endproc %a.addr = alloca i8*, align 8 store i8* %a, i8** %a.addr, align 8 %0 = load i8** %a.addr, align 8 @@ -631,5 +638,2504 @@ entry: ret void } +; test6a: Address-of local taken (j = &a) +; no ssp attribute +; Requires no protector. +define void @test6a() nounwind uwtable { +entry: +; LINUX-I386: test6a: +; LINUX-I386-NOT: calll __stack_chk_fail +; LINUX-I386: .cfi_endproc + +; LINUX-X64: test6a: +; LINUX-X64-NOT: callq __stack_chk_fail +; LINUX-X64: .cfi_endproc + +; LINUX-KERNEL-X64: test6a: +; LINUX-KERNEL-X64-NOT: callq __stack_chk_fail +; LINUX-KERNEL-X64: .cfi_endproc + +; DARWIN-X64: test6a: +; DARWIN-X64-NOT: callq ___stack_chk_fail +; DARWIN-X64: .cfi_endproc + %retval = alloca i32, align 4 + %a = alloca i32, align 4 + %j = alloca i32*, align 8 + store i32 0, i32* %retval + %0 = load i32* %a, align 4 + %add = add nsw i32 %0, 1 + store i32 %add, i32* %a, align 4 + store i32* %a, i32** %j, align 8 + ret void +} + +; test6b: Address-of local taken (j = &a) +; ssp attribute +; Requires no protector. +define void @test6b() nounwind uwtable ssp { +entry: +; LINUX-I386: test6b: +; LINUX-I386-NOT: calll __stack_chk_fail +; LINUX-I386: .cfi_endproc + +; LINUX-X64: test6b: +; LINUX-X64-NOT: callq __stack_chk_fail +; LINUX-X64: .cfi_endproc + +; LINUX-KERNEL-X64: test6b: +; LINUX-KERNEL-X64-NOT: callq __stack_chk_fail +; LINUX-KERNEL-X64: .cfi_endproc + +; DARWIN-X64: test6b: +; DARWIN-X64-NOT: callq ___stack_chk_fail +; DARWIN-X64: .cfi_endproc + %retval = alloca i32, align 4 + %a = alloca i32, align 4 + %j = alloca i32*, align 8 + store i32 0, i32* %retval + %0 = load i32* %a, align 4 + %add = add nsw i32 %0, 1 + store i32 %add, i32* %a, align 4 + store i32* %a, i32** %j, align 8 + ret void +} + +; test6c: Address-of local taken (j = &a) +; sspstrong attribute +; Requires protector. +define void @test6c() nounwind uwtable sspstrong { +entry: +; LINUX-I386: test6c: +; LINUX-I386: mov{{l|q}} %gs: +; LINUX-I386: calll __stack_chk_fail + +; LINUX-X64: test6c: +; LINUX-X64: mov{{l|q}} %fs: +; LINUX-X64: callq __stack_chk_fail + +; LINUX-KERNEL-X64: test6c: +; LINUX-KERNEL-X64: mov{{l|q}} %gs: +; LINUX-KERNEL-X64: callq __stack_chk_fail + +; DARWIN-X64: test6c: +; DARWIN-X64: mov{{l|q}} ___stack_chk_guard +; DARWIN-X64: callq ___stack_chk_fail + %retval = alloca i32, align 4 + %a = alloca i32, align 4 + %j = alloca i32*, align 8 + store i32 0, i32* %retval + %0 = load i32* %a, align 4 + %add = add nsw i32 %0, 1 + store i32 %add, i32* %a, align 4 + store i32* %a, i32** %j, align 8 + ret void +} + +; test6d: Address-of local taken (j = &a) +; sspreq attribute +; Requires protector. +define void @test6d() nounwind uwtable sspreq { +entry: +; LINUX-I386: test6d: +; LINUX-I386: mov{{l|q}} %gs: +; LINUX-I386: calll __stack_chk_fail + +; LINUX-X64: test6d: +; LINUX-X64: mov{{l|q}} %fs: +; LINUX-X64: callq __stack_chk_fail + +; LINUX-KERNEL-X64: test6d: +; LINUX-KERNEL-X64: mov{{l|q}} %gs: +; LINUX-KERNEL-X64: callq __stack_chk_fail + +; DARWIN-X64: test6d: +; DARWIN-X64: mov{{l|q}} ___stack_chk_guard +; DARWIN-X64: callq ___stack_chk_fail + %retval = alloca i32, align 4 + %a = alloca i32, align 4 + %j = alloca i32*, align 8 + store i32 0, i32* %retval + %0 = load i32* %a, align 4 + %add = add nsw i32 %0, 1 + store i32 %add, i32* %a, align 4 + store i32* %a, i32** %j, align 8 + ret void +} + +; test7a: PtrToInt Cast +; no ssp attribute +; Requires no protector. +define void @test7a() nounwind uwtable readnone { +entry: +; LINUX-I386: test7a: +; LINUX-I386-NOT: calll __stack_chk_fail +; LINUX-I386: .cfi_endproc + +; LINUX-X64: test7a: +; LINUX-X64-NOT: callq __stack_chk_fail +; LINUX-X64: .cfi_endproc + +; LINUX-KERNEL-X64: test7a: +; LINUX-KERNEL-X64-NOT: callq __stack_chk_fail +; LINUX-KERNEL-X64: .cfi_endproc + +; DARWIN-X64: test7a: +; DARWIN-X64-NOT: callq ___stack_chk_fail +; DARWIN-X64: .cfi_endproc + %a = alloca i32, align 4 + %0 = ptrtoint i32* %a to i64 + %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i64 %0) + ret void +} + +; test7b: PtrToInt Cast +; ssp attribute +; Requires no protector. +define void @test7b() nounwind uwtable readnone ssp { +entry: +; LINUX-I386: test7b: +; LINUX-I386-NOT: calll __stack_chk_fail +; LINUX-I386: .cfi_endproc + +; LINUX-X64: test7b: +; LINUX-X64-NOT: callq __stack_chk_fail +; LINUX-X64: .cfi_endproc + +; LINUX-KERNEL-X64: test7b: +; LINUX-KERNEL-X64-NOT: callq __stack_chk_fail +; LINUX-KERNEL-X64: .cfi_endproc + +; DARWIN-X64: test7b: +; DARWIN-X64-NOT: callq ___stack_chk_fail +; DARWIN-X64: .cfi_endproc + %a = alloca i32, align 4 + %0 = ptrtoint i32* %a to i64 + %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i64 %0) + ret void +} + +; test7c: PtrToInt Cast +; sspstrong attribute +; Requires protector. +define void @test7c() nounwind uwtable readnone sspstrong { +entry: +; LINUX-I386: test7c: +; LINUX-I386: mov{{l|q}} %gs: +; LINUX-I386: calll __stack_chk_fail + +; LINUX-X64: test7c: +; LINUX-X64: mov{{l|q}} %fs: +; LINUX-X64: callq __stack_chk_fail + +; LINUX-KERNEL-X64: test7c: +; LINUX-KERNEL-X64: mov{{l|q}} %gs: +; LINUX-KERNEL-X64: callq __stack_chk_fail + +; DARWIN-X64: test7c: +; DARWIN-X64: mov{{l|q}} ___stack_chk_guard +; DARWIN-X64: callq ___stack_chk_fail + %a = alloca i32, align 4 + %0 = ptrtoint i32* %a to i64 + %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i64 %0) + ret void +} + +; test7d: PtrToInt Cast +; sspreq attribute +; Requires protector. +define void @test7d() nounwind uwtable readnone sspreq { +entry: +; LINUX-I386: test7d: +; LINUX-I386: mov{{l|q}} %gs: +; LINUX-I386: calll __stack_chk_fail + +; LINUX-X64: test7d: +; LINUX-X64: mov{{l|q}} %fs: +; LINUX-X64: callq __stack_chk_fail + +; LINUX-KERNEL-X64: test7d: +; LINUX-KERNEL-X64: mov{{l|q}} %gs: +; LINUX-KERNEL-X64: callq __stack_chk_fail + +; DARWIN-X64: test7d: +; DARWIN-X64: mov{{l|q}} ___stack_chk_guard +; DARWIN-X64: callq ___stack_chk_fail + %a = alloca i32, align 4 + %0 = ptrtoint i32* %a to i64 + %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i64 %0) + ret void +} + +; test8a: Passing addr-of to function call +; no ssp attribute +; Requires no protector. +define void @test8a() nounwind uwtable { +entry: +; LINUX-I386: test8a: +; LINUX-I386-NOT: calll __stack_chk_fail +; LINUX-I386: .cfi_endproc + +; LINUX-X64: test8a: +; LINUX-X64-NOT: callq __stack_chk_fail +; LINUX-X64: .cfi_endproc + +; LINUX-KERNEL-X64: test8a: +; LINUX-KERNEL-X64-NOT: callq __stack_chk_fail +; LINUX-KERNEL-X64: .cfi_endproc + +; DARWIN-X64: test8a: +; DARWIN-X64-NOT: callq ___stack_chk_fail +; DARWIN-X64: .cfi_endproc + %b = alloca i32, align 4 + call void @funcall(i32* %b) nounwind + ret void +} + +; test8b: Passing addr-of to function call +; ssp attribute +; Requires no protector. +define void @test8b() nounwind uwtable ssp { +entry: +; LINUX-I386: test8b: +; LINUX-I386-NOT: calll __stack_chk_fail +; LINUX-I386: .cfi_endproc + +; LINUX-X64: test8b: +; LINUX-X64-NOT: callq __stack_chk_fail +; LINUX-X64: .cfi_endproc + +; LINUX-KERNEL-X64: test8b: +; LINUX-KERNEL-X64-NOT: callq __stack_chk_fail +; LINUX-KERNEL-X64: .cfi_endproc + +; DARWIN-X64: test8b: +; DARWIN-X64-NOT: callq ___stack_chk_fail +; DARWIN-X64: .cfi_endproc + %b = alloca i32, align 4 + call void @funcall(i32* %b) nounwind + ret void +} + +; test8c: Passing addr-of to function call +; sspstrong attribute +; Requires protector. +define void @test8c() nounwind uwtable sspstrong { +entry: +; LINUX-I386: test8c: +; LINUX-I386: mov{{l|q}} %gs: +; LINUX-I386: calll __stack_chk_fail + +; LINUX-X64: test8c: +; LINUX-X64: mov{{l|q}} %fs: +; LINUX-X64: callq __stack_chk_fail + +; LINUX-KERNEL-X64: test8c: +; LINUX-KERNEL-X64: mov{{l|q}} %gs: +; LINUX-KERNEL-X64: callq __stack_chk_fail + +; DARWIN-X64: test8c: +; DARWIN-X64: mov{{l|q}} ___stack_chk_guard +; DARWIN-X64: callq ___stack_chk_fail + %b = alloca i32, align 4 + call void @funcall(i32* %b) nounwind + ret void +} + +; test8d: Passing addr-of to function call +; sspreq attribute +; Requires protector. +define void @test8d() nounwind uwtable sspreq { +entry: +; LINUX-I386: test8d: +; LINUX-I386: mov{{l|q}} %gs: +; LINUX-I386: calll __stack_chk_fail + +; LINUX-X64: test8d: +; LINUX-X64: mov{{l|q}} %fs: +; LINUX-X64: callq __stack_chk_fail + +; LINUX-KERNEL-X64: test8d: +; LINUX-KERNEL-X64: mov{{l|q}} %gs: +; LINUX-KERNEL-X64: callq __stack_chk_fail + +; DARWIN-X64: test8d: +; DARWIN-X64: mov{{l|q}} ___stack_chk_guard +; DARWIN-X64: callq ___stack_chk_fail + %b = alloca i32, align 4 + call void @funcall(i32* %b) nounwind + ret void +} + +; test9a: Addr-of in select instruction +; no ssp attribute +; Requires no protector. +define void @test9a() nounwind uwtable { +entry: +; LINUX-I386: test9a: +; LINUX-I386-NOT: calll __stack_chk_fail +; LINUX-I386: .cfi_endproc + +; LINUX-X64: test9a: +; LINUX-X64-NOT: callq __stack_chk_fail +; LINUX-X64: .cfi_endproc + +; LINUX-KERNEL-X64: test9a: +; LINUX-KERNEL-X64-NOT: callq __stack_chk_fail +; LINUX-KERNEL-X64: .cfi_endproc + +; DARWIN-X64: test9a: +; DARWIN-X64-NOT: callq ___stack_chk_fail +; DARWIN-X64: .cfi_endproc + %x = alloca double, align 8 + %call = call double @testi_aux() nounwind + store double %call, double* %x, align 8 + %cmp2 = fcmp ogt double %call, 0.000000e+00 + %y.1 = select i1 %cmp2, double* %x, double* null + %call2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), double* %y.1) + ret void +} + +; test9b: Addr-of in select instruction +; ssp attribute +; Requires no protector. +define void @test9b() nounwind uwtable ssp { +entry: +; LINUX-I386: test9b: +; LINUX-I386-NOT: calll __stack_chk_fail +; LINUX-I386: .cfi_endproc + +; LINUX-X64: test9b: +; LINUX-X64-NOT: callq __stack_chk_fail +; LINUX-X64: .cfi_endproc + +; LINUX-KERNEL-X64: test9b: +; LINUX-KERNEL-X64-NOT: callq __stack_chk_fail +; LINUX-KERNEL-X64: .cfi_endproc + +; DARWIN-X64: test9b: +; DARWIN-X64-NOT: callq ___stack_chk_fail +; DARWIN-X64: .cfi_endproc + %x = alloca double, align 8 + %call = call double @testi_aux() nounwind + store double %call, double* %x, align 8 + %cmp2 = fcmp ogt double %call, 0.000000e+00 + %y.1 = select i1 %cmp2, double* %x, double* null + %call2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), double* %y.1) + ret void +} + +; test9c: Addr-of in select instruction +; sspstrong attribute +; Requires protector. +define void @test9c() nounwind uwtable sspstrong { +entry: +; LINUX-I386: test9c: +; LINUX-I386: mov{{l|q}} %gs: +; LINUX-I386: calll __stack_chk_fail + +; LINUX-X64: test9c: +; LINUX-X64: mov{{l|q}} %fs: +; LINUX-X64: callq __stack_chk_fail + +; LINUX-KERNEL-X64: test9c: +; LINUX-KERNEL-X64: mov{{l|q}} %gs: +; LINUX-KERNEL-X64: callq __stack_chk_fail + +; DARWIN-X64: test9c: +; DARWIN-X64: mov{{l|q}} ___stack_chk_guard +; DARWIN-X64: callq ___stack_chk_fail + %x = alloca double, align 8 + %call = call double @testi_aux() nounwind + store double %call, double* %x, align 8 + %cmp2 = fcmp ogt double %call, 0.000000e+00 + %y.1 = select i1 %cmp2, double* %x, double* null + %call2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), double* %y.1) + ret void +} + +; test9d: Addr-of in select instruction +; sspreq attribute +; Requires protector. +define void @test9d() nounwind uwtable sspreq { +entry: +; LINUX-I386: test9d: +; LINUX-I386: mov{{l|q}} %gs: +; LINUX-I386: calll __stack_chk_fail + +; LINUX-X64: test9d: +; LINUX-X64: mov{{l|q}} %fs: +; LINUX-X64: callq __stack_chk_fail + +; LINUX-KERNEL-X64: test9d: +; LINUX-KERNEL-X64: mov{{l|q}} %gs: +; LINUX-KERNEL-X64: callq __stack_chk_fail + +; DARWIN-X64: test9d: +; DARWIN-X64: mov{{l|q}} ___stack_chk_guard +; DARWIN-X64: callq ___stack_chk_fail + %x = alloca double, align 8 + %call = call double @testi_aux() nounwind + store double %call, double* %x, align 8 + %cmp2 = fcmp ogt double %call, 0.000000e+00 + %y.1 = select i1 %cmp2, double* %x, double* null + %call2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), double* %y.1) + ret void +} + +; test10a: Addr-of in phi instruction +; no ssp attribute +; Requires no protector. +define void @test10a() nounwind uwtable { +entry: +; LINUX-I386: test10a: +; LINUX-I386-NOT: calll __stack_chk_fail +; LINUX-I386: .cfi_endproc + +; LINUX-X64: test10a: +; LINUX-X64-NOT: callq __stack_chk_fail +; LINUX-X64: .cfi_endproc + +; LINUX-KERNEL-X64: test10a: +; LINUX-KERNEL-X64-NOT: callq __stack_chk_fail +; LINUX-KERNEL-X64: .cfi_endproc + +; DARWIN-X64: test10a: +; DARWIN-X64-NOT: callq ___stack_chk_fail +; DARWIN-X64: .cfi_endproc + %x = alloca double, align 8 + %call = call double @testi_aux() nounwind + store double %call, double* %x, align 8 + %cmp = fcmp ogt double %call, 3.140000e+00 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + %call1 = call double @testi_aux() nounwind + store double %call1, double* %x, align 8 + br label %if.end4 + +if.else: ; preds = %entry + %cmp2 = fcmp ogt double %call, 1.000000e+00 + br i1 %cmp2, label %if.then3, label %if.end4 + +if.then3: ; preds = %if.else + br label %if.end4 + +if.end4: ; preds = %if.else, %if.then3, %if.then + %y.0 = phi double* [ null, %if.then ], [ %x, %if.then3 ], [ null, %if.else ] + %call5 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), double* %y.0) nounwind + ret void +} + +; test10b: Addr-of in phi instruction +; ssp attribute +; Requires no protector. +define void @test10b() nounwind uwtable ssp { +entry: +; LINUX-I386: test10b: +; LINUX-I386-NOT: calll __stack_chk_fail +; LINUX-I386: .cfi_endproc + +; LINUX-X64: test10b: +; LINUX-X64-NOT: callq __stack_chk_fail +; LINUX-X64: .cfi_endproc + +; LINUX-KERNEL-X64: test10b: +; LINUX-KERNEL-X64-NOT: callq __stack_chk_fail +; LINUX-KERNEL-X64: .cfi_endproc + +; DARWIN-X64: test10b: +; DARWIN-X64-NOT: callq ___stack_chk_fail +; DARWIN-X64: .cfi_endproc + %x = alloca double, align 8 + %call = call double @testi_aux() nounwind + store double %call, double* %x, align 8 + %cmp = fcmp ogt double %call, 3.140000e+00 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + %call1 = call double @testi_aux() nounwind + store double %call1, double* %x, align 8 + br label %if.end4 + +if.else: ; preds = %entry + %cmp2 = fcmp ogt double %call, 1.000000e+00 + br i1 %cmp2, label %if.then3, label %if.end4 + +if.then3: ; preds = %if.else + br label %if.end4 + +if.end4: ; preds = %if.else, %if.then3, %if.then + %y.0 = phi double* [ null, %if.then ], [ %x, %if.then3 ], [ null, %if.else ] + %call5 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), double* %y.0) nounwind + ret void +} + +; test10c: Addr-of in phi instruction +; sspstrong attribute +; Requires protector. +define void @test10c() nounwind uwtable sspstrong { +entry: +; LINUX-I386: test10c: +; LINUX-I386: mov{{l|q}} %gs: +; LINUX-I386: calll __stack_chk_fail + +; LINUX-X64: test10c: +; LINUX-X64: mov{{l|q}} %fs: +; LINUX-X64: callq __stack_chk_fail + +; LINUX-KERNEL-X64: test10c: +; LINUX-KERNEL-X64: mov{{l|q}} %gs: +; LINUX-KERNEL-X64: callq __stack_chk_fail + +; DARWIN-X64: test10c: +; DARWIN-X64: mov{{l|q}} ___stack_chk_guard +; DARWIN-X64: callq ___stack_chk_fail + %x = alloca double, align 8 + %call = call double @testi_aux() nounwind + store double %call, double* %x, align 8 + %cmp = fcmp ogt double %call, 3.140000e+00 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + %call1 = call double @testi_aux() nounwind + store double %call1, double* %x, align 8 + br label %if.end4 + +if.else: ; preds = %entry + %cmp2 = fcmp ogt double %call, 1.000000e+00 + br i1 %cmp2, label %if.then3, label %if.end4 + +if.then3: ; preds = %if.else + br label %if.end4 + +if.end4: ; preds = %if.else, %if.then3, %if.then + %y.0 = phi double* [ null, %if.then ], [ %x, %if.then3 ], [ null, %if.else ] + %call5 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), double* %y.0) nounwind + ret void +} + +; test10d: Addr-of in phi instruction +; sspreq attribute +; Requires protector. +define void @test10d() nounwind uwtable sspreq { +entry: +; LINUX-I386: test10d: +; LINUX-I386: mov{{l|q}} %gs: +; LINUX-I386: calll __stack_chk_fail + +; LINUX-X64: test10d: +; LINUX-X64: mov{{l|q}} %fs: +; LINUX-X64: callq __stack_chk_fail + +; LINUX-KERNEL-X64: test10d: +; LINUX-KERNEL-X64: mov{{l|q}} %gs: +; LINUX-KERNEL-X64: callq __stack_chk_fail + +; DARWIN-X64: test10d: +; DARWIN-X64: mov{{l|q}} ___stack_chk_guard +; DARWIN-X64: callq ___stack_chk_fail + %x = alloca double, align 8 + %call = call double @testi_aux() nounwind + store double %call, double* %x, align 8 + %cmp = fcmp ogt double %call, 3.140000e+00 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + %call1 = call double @testi_aux() nounwind + store double %call1, double* %x, align 8 + br label %if.end4 + +if.else: ; preds = %entry + %cmp2 = fcmp ogt double %call, 1.000000e+00 + br i1 %cmp2, label %if.then3, label %if.end4 + +if.then3: ; preds = %if.else + br label %if.end4 + +if.end4: ; preds = %if.else, %if.then3, %if.then + %y.0 = phi double* [ null, %if.then ], [ %x, %if.then3 ], [ null, %if.else ] + %call5 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), double* %y.0) nounwind + ret void +} + +; test11a: Addr-of struct element. (GEP followed by store). +; no ssp attribute +; Requires no protector. +define void @test11a() nounwind uwtable { +entry: +; LINUX-I386: test11a: +; LINUX-I386-NOT: calll __stack_chk_fail +; LINUX-I386: .cfi_endproc + +; LINUX-X64: test11a: +; LINUX-X64-NOT: callq __stack_chk_fail +; LINUX-X64: .cfi_endproc + +; LINUX-KERNEL-X64: test11a: +; LINUX-KERNEL-X64-NOT: callq __stack_chk_fail +; LINUX-KERNEL-X64: .cfi_endproc + +; DARWIN-X64: test11a: +; DARWIN-X64-NOT: callq ___stack_chk_fail +; DARWIN-X64: .cfi_endproc + %c = alloca %struct.pair, align 4 + %b = alloca i32*, align 8 + %y = getelementptr inbounds %struct.pair* %c, i32 0, i32 1 + store i32* %y, i32** %b, align 8 + %0 = load i32** %b, align 8 + %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i32* %0) + ret void +} + +; test11b: Addr-of struct element. (GEP followed by store). +; ssp attribute +; Requires no protector. +define void @test11b() nounwind uwtable ssp { +entry: +; LINUX-I386: test11b: +; LINUX-I386-NOT: calll __stack_chk_fail +; LINUX-I386: .cfi_endproc + +; LINUX-X64: test11b: +; LINUX-X64-NOT: callq __stack_chk_fail +; LINUX-X64: .cfi_endproc + +; LINUX-KERNEL-X64: test11b: +; LINUX-KERNEL-X64-NOT: callq __stack_chk_fail +; LINUX-KERNEL-X64: .cfi_endproc + +; DARWIN-X64: test11b: +; DARWIN-X64-NOT: callq ___stack_chk_fail +; DARWIN-X64: .cfi_endproc + %c = alloca %struct.pair, align 4 + %b = alloca i32*, align 8 + %y = getelementptr inbounds %struct.pair* %c, i32 0, i32 1 + store i32* %y, i32** %b, align 8 + %0 = load i32** %b, align 8 + %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i32* %0) + ret void +} + +; test11c: Addr-of struct element. (GEP followed by store). +; sspstrong attribute +; Requires protector. +define void @test11c() nounwind uwtable sspstrong { +entry: +; LINUX-I386: test11c: +; LINUX-I386: mov{{l|q}} %gs: +; LINUX-I386: calll __stack_chk_fail + +; LINUX-X64: test11c: +; LINUX-X64: mov{{l|q}} %fs: +; LINUX-X64: callq __stack_chk_fail + +; LINUX-KERNEL-X64: test11c: +; LINUX-KERNEL-X64: mov{{l|q}} %gs: +; LINUX-KERNEL-X64: callq __stack_chk_fail + +; DARWIN-X64: test11c: +; DARWIN-X64: mov{{l|q}} ___stack_chk_guard +; DARWIN-X64: callq ___stack_chk_fail + %c = alloca %struct.pair, align 4 + %b = alloca i32*, align 8 + %y = getelementptr inbounds %struct.pair* %c, i32 0, i32 1 + store i32* %y, i32** %b, align 8 + %0 = load i32** %b, align 8 + %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i32* %0) + ret void +} + +; test11d: Addr-of struct element. (GEP followed by store). +; sspreq attribute +; Requires protector. +define void @test11d() nounwind uwtable sspreq { +entry: +; LINUX-I386: test11d: +; LINUX-I386: mov{{l|q}} %gs: +; LINUX-I386: calll __stack_chk_fail + +; LINUX-X64: test11d: +; LINUX-X64: mov{{l|q}} %fs: +; LINUX-X64: callq __stack_chk_fail + +; LINUX-KERNEL-X64: test11d: +; LINUX-KERNEL-X64: mov{{l|q}} %gs: +; LINUX-KERNEL-X64: callq __stack_chk_fail + +; DARWIN-X64: test11d: +; DARWIN-X64: mov{{l|q}} ___stack_chk_guard +; DARWIN-X64: callq ___stack_chk_fail + %c = alloca %struct.pair, align 4 + %b = alloca i32*, align 8 + %y = getelementptr inbounds %struct.pair* %c, i32 0, i32 1 + store i32* %y, i32** %b, align 8 + %0 = load i32** %b, align 8 + %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i32* %0) + ret void +} + +; test12a: Addr-of struct element, GEP followed by ptrtoint. +; no ssp attribute +; Requires no protector. +define void @test12a() nounwind uwtable { +entry: +; LINUX-I386: test12a: +; LINUX-I386-NOT: calll __stack_chk_fail +; LINUX-I386: .cfi_endproc |