Index: include/llvm/CodeGen/StackProtector.h =================================================================== --- include/llvm/CodeGen/StackProtector.h +++ include/llvm/CodeGen/StackProtector.h @@ -29,7 +29,7 @@ class Module; class PHINode; -class StackProtector : public FunctionPass { +class StackProtectorAnalysis : public FunctionPass { public: /// SSPLayoutKind. Stack Smashing Protection (SSP) rules require that /// vulnerable stack allocations are located close the stack protector. @@ -44,26 +44,22 @@ ///< triggered protection. 3rd closest to the protector. }; +private: /// A mapping of AllocaInsts to their required SSP layout. typedef ValueMap SSPLayoutMap; -private: - const TargetMachine *TM; - - /// TLI - Keep a pointer of a TargetLowering to consult for determining - /// target type sizes. - const TargetLoweringBase *TLI; - const Triple Trip; - - Function *F; - Module *M; - - DominatorTree *DT; - /// Layout - Mapping of allocations to the required SSPLayoutKind. /// StackProtector analysis will update this map when determining if an /// AllocaInst triggers a stack protector. + /// The rules are slightly different for Darwin platforms, so the information + /// for those platforms are stored in DarwinLayout. SSPLayoutMap Layout; + SSPLayoutMap DarwinLayout; + + /// Store whether or not this function needs a stack protector - non-Darwin. + bool RequiresStackProtector; + /// Store whether or not this function needs a stack protector - Darwin. + bool DarwinRequiresStackProtector; /// \brief The minimum size of buffers that will receive stack smashing /// protection when -fstack-protection is used. @@ -75,6 +71,66 @@ /// times. SmallPtrSet VisitedPHIs; + Function *F; + Module *M; + + /// ContainsProtectableArray - Check whether the type either is an array or + /// contains an array of sufficient size so that we need stack protectors + /// for it. + /// \param [out] IsLarge is set to true if a protectable array is found and + /// it is "large" ( >= ssp-buffer-size). In the case of a structure with + /// multiple arrays, this gets set if any of them is large. + bool ContainsProtectableArray(Type *Ty, bool &IsLarge, const bool isDarwin, + bool Strong = false, + bool InStruct = false) const; + + /// \brief Check whether a stack allocation has its address taken. + bool HasAddressTaken(const Instruction *AI); + +public: + static char ID; // Pass identification, replacement for typeid. + StackProtectorAnalysis() : FunctionPass(ID), SSPBufferSize(8) { + initializeStackProtectorAnalysisPass(*PassRegistry::getPassRegistry()); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } + + void releaseMemory() override { + Layout.clear(); + DarwinLayout.clear(); + }; + + SSPLayoutKind getSSPLayout(const AllocaInst *AI, const bool isDarwin) const; + + bool runOnFunction(Function &Fn) override; + + bool doAnalysis(Function &Fn); + + /// RequiresStackProtector - Check whether or not this function needs a + /// stack protector based upon the stack protector level. + bool requiresStackProtector(const bool isDarwin); + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + void dump(); +#endif +}; + +class StackProtector : public FunctionPass { +private: + const TargetMachine *TM; + + /// TLI - Keep a pointer of a TargetLowering to consult for determining + /// target type sizes. + const TargetLoweringBase *TLI; + const Triple Trip; + + Function *F; + Module *M; + + DominatorTree *DT; + // A prologue is generated. bool HasPrologue = false; @@ -93,45 +149,24 @@ /// check fails. BasicBlock *CreateFailBB(); - /// ContainsProtectableArray - Check whether the type either is an array or - /// contains an array of sufficient size so that we need stack protectors - /// for it. - /// \param [out] IsLarge is set to true if a protectable array is found and - /// it is "large" ( >= ssp-buffer-size). In the case of a structure with - /// multiple arrays, this gets set if any of them is large. - bool ContainsProtectableArray(Type *Ty, bool &IsLarge, 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(); - public: static char ID; // Pass identification, replacement for typeid. - StackProtector() - : FunctionPass(ID), TM(nullptr), TLI(nullptr), SSPBufferSize(0) { + StackProtector() : FunctionPass(ID), TM(nullptr), TLI(nullptr) { initializeStackProtectorPass(*PassRegistry::getPassRegistry()); } StackProtector(const TargetMachine *TM) - : FunctionPass(ID), TM(TM), TLI(nullptr), Trip(TM->getTargetTriple()), - SSPBufferSize(8) { + : FunctionPass(ID), TM(TM), TLI(nullptr), Trip(TM->getTargetTriple()) { initializeStackProtectorPass(*PassRegistry::getPassRegistry()); } void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addPreserved(); + AU.addRequired(); } - SSPLayoutKind getSSPLayout(const AllocaInst *AI) const; - // Return true if StackProtector is supposed to be handled by SelectionDAG. bool shouldEmitSDCheck(const BasicBlock &BB) const; - void adjustForColoring(const AllocaInst *From, const AllocaInst *To); - bool runOnFunction(Function &Fn) override; }; } // end namespace llvm Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -329,6 +329,7 @@ void initializeSpillPlacementPass(PassRegistry&); void initializeStackColoringPass(PassRegistry&); void initializeStackMapLivenessPass(PassRegistry&); +void initializeStackProtectorAnalysisPass(PassRegistry&); void initializeStackProtectorPass(PassRegistry&); void initializeStackSlotColoringPass(PassRegistry&); void initializeStraightLineStrengthReducePass(PassRegistry &); Index: lib/CodeGen/CodeGen.cpp =================================================================== --- lib/CodeGen/CodeGen.cpp +++ lib/CodeGen/CodeGen.cpp @@ -80,6 +80,7 @@ initializeStackMapLivenessPass(Registry); initializeLiveDebugValuesPass(Registry); initializeSafeStackPass(Registry); + initializeStackProtectorAnalysisPass(Registry); initializeStackProtectorPass(Registry); initializeStackSlotColoringPass(Registry); initializeTailDuplicatePassPass(Registry); Index: lib/CodeGen/LocalStackSlotAllocation.cpp =================================================================== --- lib/CodeGen/LocalStackSlotAllocation.cpp +++ lib/CodeGen/LocalStackSlotAllocation.cpp @@ -93,7 +93,7 @@ void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); - AU.addRequired(); + AU.addRequired(); MachineFunctionPass::getAnalysisUsage(AU); } @@ -195,10 +195,11 @@ MachineFrameInfo &MFI = Fn.getFrameInfo(); const TargetFrameLowering &TFI = *Fn.getSubtarget().getFrameLowering(); bool StackGrowsDown = - TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown; + TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown; int64_t Offset = 0; unsigned MaxAlign = 0; - StackProtector *SP = &getAnalysis(); + StackProtectorAnalysis *SPA = &getAnalysis(); + const bool isDarwin = Fn.getTarget().getTargetTriple().isOSDarwin(); // Make sure that the stack protector comes before the local variables on the // stack. @@ -218,16 +219,16 @@ if (MFI.getStackProtectorIndex() == (int)i) continue; - switch (SP->getSSPLayout(MFI.getObjectAllocation(i))) { - case StackProtector::SSPLK_None: + switch (SPA->getSSPLayout(MFI.getObjectAllocation(i), isDarwin)) { + case StackProtectorAnalysis::SSPLK_None: continue; - case StackProtector::SSPLK_SmallArray: + case StackProtectorAnalysis::SSPLK_SmallArray: SmallArrayObjs.insert(i); continue; - case StackProtector::SSPLK_AddrOf: + case StackProtectorAnalysis::SSPLK_AddrOf: AddrOfObjs.insert(i); continue; - case StackProtector::SSPLK_LargeArray: + case StackProtectorAnalysis::SSPLK_LargeArray: LargeArrayObjs.insert(i); continue; } Index: lib/CodeGen/PrologEpilogInserter.cpp =================================================================== --- lib/CodeGen/PrologEpilogInserter.cpp +++ lib/CodeGen/PrologEpilogInserter.cpp @@ -144,7 +144,7 @@ false, false) INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) -INITIALIZE_PASS_DEPENDENCY(StackProtector) +INITIALIZE_PASS_DEPENDENCY(StackProtectorAnalysis) INITIALIZE_TM_PASS_END(PEI, "prologepilog", "Prologue/Epilogue Insertion & Frame Finalization", false, false) @@ -162,11 +162,10 @@ AU.setPreservesCFG(); AU.addPreserved(); AU.addPreserved(); - AU.addRequired(); + AU.addRequired(); MachineFunctionPass::getAnalysisUsage(AU); } - /// StackObjSet - A set of stack object indexes typedef SmallSetVector StackObjSet; @@ -706,10 +705,11 @@ /// void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) { const TargetFrameLowering &TFI = *Fn.getSubtarget().getFrameLowering(); - StackProtector *SP = &getAnalysis(); + StackProtectorAnalysis *SPA = &getAnalysis(); + const bool isDarwin = Fn.getTarget().getTargetTriple().isOSDarwin(); bool StackGrowsDown = - TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown; + TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown; // Loop over all of the stack objects, assigning sequential addresses... MachineFrameInfo &MFI = Fn.getFrameInfo(); @@ -852,28 +852,32 @@ EHRegNodeFrameIndex == (int)i) continue; - switch (SP->getSSPLayout(MFI.getObjectAllocation(i))) { - case StackProtector::SSPLK_None: + switch (SPA->getSSPLayout(MFI.getObjectAllocation(i), isDarwin)) { + case StackProtectorAnalysis::SSPLK_None: continue; - case StackProtector::SSPLK_SmallArray: + case StackProtectorAnalysis::SSPLK_SmallArray: SmallArrayObjs.insert(i); continue; - case StackProtector::SSPLK_AddrOf: + case StackProtectorAnalysis::SSPLK_AddrOf: AddrOfObjs.insert(i); continue; - case StackProtector::SSPLK_LargeArray: + case StackProtectorAnalysis::SSPLK_LargeArray: LargeArrayObjs.insert(i); continue; } llvm_unreachable("Unexpected SSPLayoutKind."); } + DEBUG(dbgs() << "Assigning LargeArrayObjs\n"); AssignProtectedObjSet(LargeArrayObjs, ProtectedObjs, MFI, StackGrowsDown, Offset, MaxAlign, Skew); + DEBUG(dbgs() << "Assigning SmallArrayObjs\n"); AssignProtectedObjSet(SmallArrayObjs, ProtectedObjs, MFI, StackGrowsDown, Offset, MaxAlign, Skew); + DEBUG(dbgs() << "Assigning AddrOfObjs\n"); AssignProtectedObjSet(AddrOfObjs, ProtectedObjs, MFI, StackGrowsDown, Offset, MaxAlign, Skew); + DEBUG(dbgs() << "Finished assigning protected objects\n"); } SmallVector ObjectsToAllocate; Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -1598,6 +1598,8 @@ LowerArguments(Fn); } } + // FIXME: StackProtector is not an analysis pass. StackProtector should not + // be used as an analysis pass here. if (getAnalysis().shouldEmitSDCheck(*LLVMBB)) { bool FunctionBasedInstrumentation = TLI->getSSPStackGuardCheck(*Fn.getParent()); Index: lib/CodeGen/StackColoring.cpp =================================================================== --- lib/CodeGen/StackColoring.cpp +++ lib/CodeGen/StackColoring.cpp @@ -278,8 +278,6 @@ VNInfo::Allocator VNInfoAllocator; /// SlotIndex analysis object. SlotIndexes *Indexes; - /// The stack protector object. - StackProtector *SP; /// The list of lifetime markers found. These markers are to be removed /// once the coloring is done. @@ -381,7 +379,6 @@ void StackColoring::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); - AU.addRequired(); MachineFunctionPass::getAnalysisUsage(AU); } @@ -810,10 +807,6 @@ Inst = Cast; } - // Allow the stack protector to adjust its value map to account for the - // upcoming replacement. - SP->adjustForColoring(From, To); - // The new alloca might not be valid in a llvm.dbg.declare for this // variable, so undef out the use to make the verifier happy. AllocaInst *FromAI = const_cast(From); @@ -979,7 +972,6 @@ MF = &Func; MFI = &MF->getFrameInfo(); Indexes = &getAnalysis(); - SP = &getAnalysis(); BlockLiveness.clear(); BasicBlocks.clear(); BasicBlockNumbering.clear(); Index: lib/CodeGen/StackProtector.cpp =================================================================== --- lib/CodeGen/StackProtector.cpp +++ lib/CodeGen/StackProtector.cpp @@ -17,6 +17,7 @@ #include "llvm/CodeGen/StackProtector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/BranchProbabilityInfo.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/ValueTracking.h" @@ -43,127 +44,260 @@ #define DEBUG_TYPE "stack-protector" STATISTIC(NumFunProtected, "Number of functions protected"); -STATISTIC(NumAddrTaken, "Number of local variables that have their address" - " taken."); static cl::opt EnableSelectionDAGSP("enable-selectiondag-sp", cl::init(true), cl::Hidden); +char StackProtectorAnalysis::ID = 0; +INITIALIZE_PASS(StackProtectorAnalysis, "stack-protector-analysis", + "Analyze need for stack protectors", true, true) char StackProtector::ID = 0; INITIALIZE_TM_PASS(StackProtector, "stack-protector", "Insert stack protectors", - false, true) + false, false) FunctionPass *llvm::createStackProtectorPass(const TargetMachine *TM) { return new StackProtector(TM); } -StackProtector::SSPLayoutKind -StackProtector::getSSPLayout(const AllocaInst *AI) const { - return AI ? Layout.lookup(AI) : SSPLK_None; +StackProtectorAnalysis::SSPLayoutKind +StackProtectorAnalysis::getSSPLayout(const AllocaInst *AI, + const bool isDarwin) const { + if (!AI) { + DEBUG(dbgs() << "SPA::getSSPLayout(null, " + << isDarwin << ") = SSPLK_None"); + return SSPLK_None; + } + DEBUG(dbgs() << "SPA::getSSPLayout("<< *AI + << ", " << isDarwin << ") = "); + SSPLayoutKind result = + isDarwin ? DarwinLayout.lookup(AI) : Layout.lookup(AI); + switch (result) { + case SSPLK_None: DEBUG(dbgs() << "SSPLK_None"); break; + case SSPLK_LargeArray: DEBUG(dbgs() << "SSPLK_LargeArray"); break; + case SSPLK_SmallArray: DEBUG(dbgs() << "SSPLK_SmallArray"); break; + case SSPLK_AddrOf: DEBUG(dbgs() << "SSPLK_AddrOf"); break; + } + DEBUG(dbgs() << "\n"); + return result; +} + +static bool hasPrologue(Function *F) { + for (const BasicBlock &BB : *F) + for (const Instruction &I : BB) + if (const CallInst *CI = dyn_cast(&I)) + if (CI->getCalledFunction() == + Intrinsic::getDeclaration(F->getParent(), + Intrinsic::stackprotector)) + return true; + return false; } -void StackProtector::adjustForColoring(const AllocaInst *From, - const AllocaInst *To) { - // When coloring replaces one alloca with another, transfer the SSPLayoutKind - // tag from the remapped to the target alloca. The remapped alloca should - // have a size smaller than or equal to the replacement alloca. - SSPLayoutMap::iterator I = Layout.find(From); - if (I != Layout.end()) { - SSPLayoutKind Kind = I->second; - Layout.erase(I); - - // Transfer the tag, but make sure that SSPLK_AddrOf does not overwrite - // SSPLK_SmallArray or SSPLK_LargeArray, and make sure that - // SSPLK_SmallArray does not overwrite SSPLK_LargeArray. - I = Layout.find(To); - if (I == Layout.end()) - Layout.insert(std::make_pair(To, Kind)); - else if (I->second != SSPLK_LargeArray && Kind != SSPLK_AddrOf) - I->second = Kind; +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +void StackProtectorAnalysis::dump() { + dbgs() << "StackProtectorAnalysis Result\n"; + for(bool isDarwin : {false, true}) { + const SSPLayoutMap& _Layout = isDarwin ? DarwinLayout : Layout; + const bool& _RequiresStackProtector = + isDarwin ? DarwinRequiresStackProtector : RequiresStackProtector; + dbgs() << "-isDarwin(" << isDarwin << ")\n"; + dbgs() << " RequiresStackProtector: " + << _RequiresStackProtector << "\n"; + for(const auto& a2layoutkind : _Layout) { + switch (a2layoutkind.second) { + case SSPLK_None: dbgs() << "SSPLK_None"; break; + case SSPLK_LargeArray: dbgs() << "SSPLK_LargeArray"; break; + case SSPLK_SmallArray: dbgs() << "SSPLK_SmallArray"; break; + case SSPLK_AddrOf: dbgs() << "SSPLK_AddrOf"; break; + } + dbgs() << " " << *(a2layoutkind.first) << "\n"; + } } } +#endif -bool StackProtector::runOnFunction(Function &Fn) { +/// \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 StackProtectorAnalysis::runOnFunction(Function &Fn) { + bool result = doAnalysis(Fn); + DEBUG(dump()); + return result; +} + +bool StackProtectorAnalysis::doAnalysis(Function &Fn) { F = &Fn; M = F->getParent(); - DominatorTreeWrapperPass *DTWP = - getAnalysisIfAvailable(); - DT = DTWP ? &DTWP->getDomTree() : nullptr; - TLI = TM->getSubtargetImpl(Fn)->getTargetLowering(); - HasPrologue = false; - HasIRCheck = false; + + RequiresStackProtector = false; + DarwinRequiresStackProtector = false; Attribute Attr = Fn.getFnAttribute("stack-protector-buffer-size"); if (Attr.isStringAttribute() && Attr.getValueAsString().getAsInteger(10, SSPBufferSize)) return false; // Invalid integer string - if (!RequiresStackProtector()) + bool Strong = false; + bool HasPrologue = hasPrologue(F); + + if (F->hasFnAttribute(Attribute::SafeStack)) + return false; + + if (F->hasFnAttribute(Attribute::StackProtectReq)) { + RequiresStackProtector = true; + DarwinRequiresStackProtector = true; + Strong = true; // Use the same heuristic as strong to determine SSPLayout + } else if (F->hasFnAttribute(Attribute::StackProtectStrong)) + Strong = true; + else if (HasPrologue) { + RequiresStackProtector = true; + DarwinRequiresStackProtector = true; + } else if (!F->hasFnAttribute(Attribute::StackProtect)) return false; + SmallVector AllocaInsts; + + for (const BasicBlock &BB : *F) { + for (const Instruction &I : BB) { + if (const AllocaInst *AI = dyn_cast(&I)) { + AllocaInsts.push_back(AI); + } + } + } + + for (const bool isDarwin : {false, true}) { + VisitedPHIs.clear(); + SSPLayoutMap& _Layout = isDarwin ? DarwinLayout : Layout; + bool& _RequiresStackProtector = isDarwin ? DarwinRequiresStackProtector + : RequiresStackProtector; + for(const AllocaInst* AI : AllocaInsts) { + if (AI->isArrayAllocation()) { + if (const auto *CI = dyn_cast(AI->getArraySize())) { + if (CI->getLimitedValue(SSPBufferSize) >= SSPBufferSize) { + // A call to alloca with size >= SSPBufferSize requires + // stack protectors. + _Layout.insert(std::make_pair(AI, SSPLK_LargeArray)); + _RequiresStackProtector = true; + } else if (Strong) { + // Require protectors for all alloca calls in strong mode. + _Layout.insert(std::make_pair(AI, SSPLK_SmallArray)); + _RequiresStackProtector = true; + } + } else { + // A call to alloca with a variable size requires protectors. + _Layout.insert(std::make_pair(AI, SSPLK_LargeArray)); + _RequiresStackProtector = true; + } + continue; + } + + bool IsLarge = false; + if (ContainsProtectableArray(AI->getAllocatedType(), IsLarge, + isDarwin, Strong)) { + _Layout.insert(std::make_pair( + AI, IsLarge ? SSPLK_LargeArray : SSPLK_SmallArray)); + _RequiresStackProtector = true; + continue; + } + + if (Strong && HasAddressTaken(AI)) { + _Layout.insert(std::make_pair(AI, SSPLK_AddrOf)); + _RequiresStackProtector = true; + } + } + } + // TODO(etienneb): Functions with funclets are not correctly supported now. // Do nothing if this is funclet-based personality. if (Fn.hasPersonalityFn()) { EHPersonality Personality = classifyEHPersonality(Fn.getPersonalityFn()); - if (isFuncletEHPersonality(Personality)) - return false; + if (isFuncletEHPersonality(Personality)) { + RequiresStackProtector = false; + DarwinRequiresStackProtector = false; + } } - ++NumFunProtected; - return InsertStackProtectors(); + return false; } /// \param [out] IsLarge is set to true if a protectable array is found and /// it is "large" ( >= ssp-buffer-size). In the case of a structure with /// multiple arrays, this gets set if any of them is large. -bool StackProtector::ContainsProtectableArray(Type *Ty, bool &IsLarge, - bool Strong, - bool InStruct) const { - if (!Ty) +bool StackProtectorAnalysis::ContainsProtectableArray(Type *Ty, bool &IsLarge, + const bool isDarwin, + bool Strong, + bool InStruct) const { + DEBUG(dbgs() << "SP::ContainsProtectableArray(" + << *Ty << ", IsLarge:" << IsLarge + << ", Strong:" << Strong + << ", InStruct: " << InStruct + << ") returns " ); + if (!Ty) { + DEBUG(dbgs() << false << "\n"); return false; + } if (ArrayType *AT = dyn_cast(Ty)) { if (!AT->getElementType()->isIntegerTy(8)) { // If we're on a non-Darwin platform or we're inside of a structure, don't // add stack protectors unless the array is a character array. // However, in strong mode any array, regardless of type and size, // triggers a protector. - if (!Strong && (InStruct || !Trip.isOSDarwin())) + if (!Strong && (InStruct || !isDarwin)) { + DEBUG(dbgs() << false << "\n"); return false; + } } // If an array has more than SSPBufferSize bytes of allocated space, then we // emit stack protectors. if (SSPBufferSize <= M->getDataLayout().getTypeAllocSize(AT)) { IsLarge = true; + DEBUG(dbgs() << true << "\n"); return true; } - if (Strong) + if (Strong) { // Require a protector for all arrays in strong mode + DEBUG(dbgs() << true << "\n"); return true; + } } const StructType *ST = dyn_cast(Ty); - if (!ST) + if (!ST) { + DEBUG(dbgs() << false << "\n"); return false; + } bool NeedsProtector = false; for (StructType::element_iterator I = ST->element_begin(), E = ST->element_end(); I != E; ++I) - if (ContainsProtectableArray(*I, IsLarge, Strong, true)) { + if (ContainsProtectableArray(*I, IsLarge, isDarwin, Strong, true)) { // If the element is a protectable array and is large (>= SSPBufferSize) // then we are done. If the protectable array is not large, then // keep looking in case a subsequent element is a large array. - if (IsLarge) + if (IsLarge) { + DEBUG(dbgs() << true << "\n"); return true; + } NeedsProtector = true; } + DEBUG(dbgs() << NeedsProtector << "\n"); return NeedsProtector; } -bool StackProtector::HasAddressTaken(const Instruction *AI) { +bool StackProtectorAnalysis::HasAddressTaken(const Instruction *AI) { for (const User *U : AI->users()) { if (const StoreInst *SI = dyn_cast(U)) { if (AI == SI->getValueOperand()) @@ -195,84 +329,29 @@ return false; } -/// \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; - bool NeedsProtector = false; - for (const BasicBlock &BB : *F) - for (const Instruction &I : BB) - if (const CallInst *CI = dyn_cast(&I)) - if (CI->getCalledFunction() == - Intrinsic::getDeclaration(F->getParent(), - Intrinsic::stackprotector)) - HasPrologue = true; - - if (F->hasFnAttribute(Attribute::SafeStack)) - return false; +bool StackProtectorAnalysis::requiresStackProtector(const bool isDarwin) { + return isDarwin ? DarwinRequiresStackProtector : RequiresStackProtector; +} - if (F->hasFnAttribute(Attribute::StackProtectReq)) { - NeedsProtector = true; - Strong = true; // Use the same heuristic as strong to determine SSPLayout - } else if (F->hasFnAttribute(Attribute::StackProtectStrong)) - Strong = true; - else if (HasPrologue) - NeedsProtector = true; - else if (!F->hasFnAttribute(Attribute::StackProtect)) - return false; +bool StackProtector::runOnFunction(Function &Fn) { + HasPrologue = false; + HasIRCheck = false; - for (const BasicBlock &BB : *F) { - for (const Instruction &I : BB) { - if (const AllocaInst *AI = dyn_cast(&I)) { - if (AI->isArrayAllocation()) { - if (const auto *CI = dyn_cast(AI->getArraySize())) { - if (CI->getLimitedValue(SSPBufferSize) >= SSPBufferSize) { - // A call to alloca with size >= SSPBufferSize requires - // stack protectors. - Layout.insert(std::make_pair(AI, SSPLK_LargeArray)); - NeedsProtector = true; - } else if (Strong) { - // Require protectors for all alloca calls in strong mode. - Layout.insert(std::make_pair(AI, SSPLK_SmallArray)); - NeedsProtector = true; - } - } else { - // A call to alloca with a variable size requires protectors. - Layout.insert(std::make_pair(AI, SSPLK_LargeArray)); - NeedsProtector = true; - } - continue; - } + F = &Fn; + M = F->getParent(); + DominatorTreeWrapperPass *DTWP = + getAnalysisIfAvailable(); + DT = DTWP ? &DTWP->getDomTree() : nullptr; + TLI = TM->getSubtargetImpl(Fn)->getTargetLowering(); - bool IsLarge = false; - if (ContainsProtectableArray(AI->getAllocatedType(), IsLarge, Strong)) { - Layout.insert(std::make_pair(AI, IsLarge ? SSPLK_LargeArray - : SSPLK_SmallArray)); - NeedsProtector = true; - continue; - } + StackProtectorAnalysis &SPA = getAnalysis(); + if (!SPA.requiresStackProtector(Trip.isOSDarwin())) + return false; - if (Strong && HasAddressTaken(AI)) { - ++NumAddrTaken; - Layout.insert(std::make_pair(AI, SSPLK_AddrOf)); - NeedsProtector = true; - } - } - } - } + HasPrologue = hasPrologue(F); - return NeedsProtector; + ++NumFunProtected; + return InsertStackProtectors(); } /// Create a stack guard loading and populate whether SelectionDAG SSP is @@ -462,5 +541,6 @@ } bool StackProtector::shouldEmitSDCheck(const BasicBlock &BB) const { + // FIXME: should this move to the analysis pass? return HasPrologue && !HasIRCheck && dyn_cast(BB.getTerminator()); } Index: test/CodeGen/AArch64/GlobalISel/legalmir2asm.mir =================================================================== --- /dev/null +++ test/CodeGen/AArch64/GlobalISel/legalmir2asm.mir @@ -0,0 +1,37 @@ +# RUN: llc -O0 -mtriple=aarch64-apple-ios -start-after=instruction-select -verify-machineinstrs -global-isel %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=IOS +# RUN: llc -O0 -mtriple=aarch64-linux-gnu -start-after=instruction-select -verify-machineinstrs -global-isel %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=LINUX-DEFAULT +# RUN: llc -O0 -mtriple=aarch64-linux-gnu -relocation-model=pic -start-after=instruction-select -verify-machineinstrs -global-isel %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=LINUX-PIC + +# Test the legalized MIR -> assembly translation. + +--- | + target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + + define void @add_s8_gpr() { ret void } +... + +--- +# CHECK-LABEL: add_s8_gpr: +name: add_s8_gpr +legalized: true +regBankSelected: true +selected: true +tracksRegLiveness: true + +registers: + - { id: 0, class: gpr32 } + - { id: 1, class: gpr32 } + - { id: 2, class: gpr32 } + +# CHECK: add w0, w0, w1 +# CHECK-NEXT: ret +body: | + bb.0: + liveins: %w0, %w1 + + %0 = COPY %w0 + %1 = COPY %w1 + %2 = ADDWrr %0, %1 + %w0 = COPY %2 + RET_ReallyLR implicit %w0 +... Index: test/CodeGen/X86/stack-protector.ll =================================================================== --- test/CodeGen/X86/stack-protector.ll +++ test/CodeGen/X86/stack-protector.ll @@ -3911,6 +3911,23 @@ ret void, !dbg !9 } +%struct.s = type { i32 } + +define i32 @test_overlapping_slots() local_unnamed_addr sspstrong { +entry: + %b = alloca i32, align 4 + %a = alloca %struct.s, align 4 + %0 = bitcast i32* %b to i8* + call void @llvm.lifetime.start(i64 4, i8* nonnull %0) + call void @fn1(i32* nonnull %b) + call void @llvm.lifetime.end(i64 4, i8* nonnull %0) + %1 = bitcast %struct.s* %a to i8* + call void @llvm.lifetime.start(i64 4, i8* nonnull %1) + call void @fn2(%struct.s* nonnull %a) + call void @llvm.lifetime.end(i64 4, i8* nonnull %1) + ret i32 1 +} + declare double @testi_aux() declare i8* @strcpy(i8*, i8*) declare i32 @printf(i8*, ...) @@ -3923,6 +3940,11 @@ declare i32* @getp() declare i32 @dummy(...) declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) +declare void @llvm.lifetime.start(i64, i8* nocapture) ; #1 +declare void @llvm.lifetime.end(i64, i8* nocapture) ; #1 +declare void @fn1(i32*) local_unnamed_addr ; #2 +declare void @fn2(%struct.s*) local_unnamed_addr ; #2 + attributes #0 = { ssp } attributes #1 = { sspstrong }