diff --git a/clang/test/Frontend/stack-usage-safestack.c b/clang/test/Frontend/stack-usage-safestack.c new file mode 100644 --- /dev/null +++ b/clang/test/Frontend/stack-usage-safestack.c @@ -0,0 +1,20 @@ +/// Check that stack frame size warnings behave the same when safe stack is enabled + +// RUN: %clang_cc1 %s -fwarn-stack-size=48 -S -o - -triple=i386-apple-darwin 2>&1 | FileCheck --check-prefix=REGULAR %s +// RUN: %clang_cc1 %s -fwarn-stack-size=1060 -S -o - -triple=i386-apple-darwin 2>&1 | FileCheck --check-prefix=IGNORE %s + +// RUN: %clang_cc1 %s -fsanitize=safe-stack -fwarn-stack-size=48 -S -o - -triple=i386-apple-darwin 2>&1 | FileCheck --check-prefix=SAFESTACK %s +// RUN: %clang_cc1 %s -fsanitize=safe-stack -fwarn-stack-size=1060 -S -o - -triple=i386-apple-darwin 2>&1 | FileCheck --check-prefix=IGNORE %s + +extern void init(int *buf, int size); +extern int use_buf(int *buf, int size); + +// REGULAR: warning: stack frame size ([[#]]) exceeds limit ([[#]]) in 'stackSizeWarning' +// SAFESTACK: warning: stack frame size ([[#]]) exceeds limit ([[#]]) in 'stackSizeWarning' +// IGNORE-NOT: stack frame size ([[#]]) exceeds limit ([[#]]) in 'stackSizeWarning' +void stackSizeWarning() { + int buf[256]; + init(buf, sizeof(buf)); + if (buf[0] < 42) + use_buf(buf, sizeof(buf)); +} diff --git a/llvm/include/llvm/CodeGen/MachineFrameInfo.h b/llvm/include/llvm/CodeGen/MachineFrameInfo.h --- a/llvm/include/llvm/CodeGen/MachineFrameInfo.h +++ b/llvm/include/llvm/CodeGen/MachineFrameInfo.h @@ -335,6 +335,9 @@ /// Not null, if shrink-wrapping found a better place for the epilogue. MachineBasicBlock *Restore = nullptr; + /// Size of the UnsafeStack Frame + uint64_t UnsafeStackSize = 0; + public: explicit MachineFrameInfo(unsigned StackAlignment, bool StackRealignable, bool ForcedRealign) @@ -773,6 +776,9 @@ MachineBasicBlock *getRestorePoint() const { return Restore; } void setRestorePoint(MachineBasicBlock *NewRestore) { Restore = NewRestore; } + uint64_t getUnsafeStackSize() const { return UnsafeStackSize; } + void setUnsafeStackSize(uint64_t Size) { UnsafeStackSize = Size; } + /// Return a set of physical registers that are pristine. /// /// Pristine registers hold a value that is useless to the current function, diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1208,7 +1208,8 @@ return; const MachineFrameInfo &FrameInfo = MF.getFrameInfo(); - uint64_t StackSize = FrameInfo.getStackSize(); + uint64_t StackSize = + FrameInfo.getStackSize() + FrameInfo.getUnsafeStackSize(); if (StackUsageStream == nullptr) { std::error_code EC; diff --git a/llvm/lib/CodeGen/MachineFunction.cpp b/llvm/lib/CodeGen/MachineFunction.cpp --- a/llvm/lib/CodeGen/MachineFunction.cpp +++ b/llvm/lib/CodeGen/MachineFunction.cpp @@ -109,6 +109,27 @@ llvm_unreachable("Invalid machine function property"); } +void setUnsafeStackSize(const Function &F, MachineFrameInfo &FrameInfo) { + if (!F.hasFnAttribute(Attribute::SafeStack)) + return; + + auto *Existing = + dyn_cast_or_null(F.getMetadata(LLVMContext::MD_annotation)); + + if (!Existing || Existing->getNumOperands() != 2) + return; + + auto *MetadataName = "unsafe-stack-size"; + if (auto &N = Existing->getOperand(0)) { + if (cast(N.get())->getString() == MetadataName) { + if (auto &Op = Existing->getOperand(1)) { + auto Val = mdconst::extract(Op)->getZExtValue(); + FrameInfo.setUnsafeStackSize(Val); + } + } + } +} + // Pin the vtable to this file. void MachineFunction::Delegate::anchor() {} @@ -177,6 +198,8 @@ /*ForcedRealign=*/CanRealignSP && F.hasFnAttribute(Attribute::StackAlignment)); + setUnsafeStackSize(F, *FrameInfo); + if (F.hasFnAttribute(Attribute::StackAlignment)) FrameInfo->ensureMaxAlignment(*F.getFnStackAlign()); diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp --- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp +++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp @@ -285,6 +285,9 @@ assert(!Failed && "Invalid warn-stack-size fn attr value"); (void)Failed; } + if (MF.getFunction().hasFnAttribute(Attribute::SafeStack)) { + StackSize += MFI.getUnsafeStackSize(); + } if (StackSize > Threshold) { DiagnosticInfoStackSize DiagStackSize(F, StackSize, Threshold, DS_Warning); F.getContext().diagnose(DiagStackSize); diff --git a/llvm/lib/CodeGen/SafeStack.cpp b/llvm/lib/CodeGen/SafeStack.cpp --- a/llvm/lib/CodeGen/SafeStack.cpp +++ b/llvm/lib/CodeGen/SafeStack.cpp @@ -49,6 +49,7 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/MDBuilder.h" +#include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" #include "llvm/IR/Use.h" @@ -645,6 +646,13 @@ // FIXME: no need to update BasePointer in leaf functions. unsigned FrameSize = alignTo(SSL.getFrameSize(), StackAlignment); + MDBuilder MDB(F.getContext()); + SmallVector Data; + Data.push_back(MDB.createString("unsafe-stack-size")); + Data.push_back(MDB.createConstant(ConstantInt::get(Int32Ty, FrameSize))); + MDNode *MD = MDTuple::get(F.getContext(), Data); + F.setMetadata(LLVMContext::MD_annotation, MD); + // Update shadow stack pointer in the function epilogue. IRB.SetInsertPoint(BasePointer->getNextNode());