================
@@ -63,6 +63,105 @@ static cl::opt<bool> 
EnableSelectionDAGSP("enable-selectiondag-sp",
 static cl::opt<bool> DisableCheckNoReturn("disable-check-noreturn-call",
                                           cl::init(false), cl::Hidden);
 
+/// Function attribute selecting MSVC's /GS (Buffer Security Check) heuristic.
+/// Emitted by clang-cl.
+static constexpr const char *GSBufferAttr = "stack-protector-gs-buffer";
+
+/// Values of the "stack-protector" metadata that may be attached to an alloca
+/// to override the heuristic for that allocation. See LangRef.
+enum SSPAllocaMD : uint32_t {
+  /// Ignore this alloca when deciding whether the function needs a protector.
+  SSPAMD_Ignore = 0,
+  /// This alloca is a buffer that requires a protector, and is laid out like a
+  /// small (< ssp-buffer-size) array.
+  SSPAMD_SmallBuffer = 1,
+  /// This alloca is a buffer that requires a protector, and is laid out like a
+  /// large (>= ssp-buffer-size) array.
+  SSPAMD_LargeBuffer = 2,
+};
+
+/// Read the "stack-protector" metadata of \p AI, if it has any. \p IsTrivial 
is
+/// set from the optional second operand, which says the allocation holds an
+/// object of trivial type.
+static std::optional<uint32_t> getSSPAllocaMD(const AllocaInst &AI,
+                                              bool &IsTrivial) {
+  IsTrivial = false;
+  const MDNode *MD = AI.getMetadata("stack-protector");
+  if (!MD || MD->getNumOperands() < 1 || MD->getNumOperands() > 2)
+    return std::nullopt;
+  const auto *CI = mdconst::dyn_extract<ConstantInt>(MD->getOperand(0));
+  if (!CI)
+    return std::nullopt;
+  if (MD->getNumOperands() == 2)
+    if (const auto *Flag = 
mdconst::dyn_extract<ConstantInt>(MD->getOperand(1)))
+      IsTrivial = !Flag->isZero();
+  // Clamp, so that a value from a newer producer errs towards more protection
+  // rather than less.
+  return CI->getLimitedValue(SSPAMD_LargeBuffer);
+}
+
+/// Returns true if the only thing \p AI's address is ever used for, besides
+/// being read and written here, is receiving the indirect return value of a
+/// call.
+///
+/// cl.exe gives such an allocation a slot in the frame's temporary area, which
+/// the cookie does not cover, and leaves it out of the GS analysis: the only
+/// code that writes it from outside is a callee, and a callee writes exactly
+/// one object of the type it returns. As soon as the address reaches anywhere
+/// else, cl.exe relocates the object into the protected region instead, so 
look
+/// for that here rather than in the frontend, which cannot see the uses.
+///
+/// Only an object cl.exe is free to relocate can end up in that area, which is
+/// why the caller also requires the allocation to hold a trivial object.
+static bool isIndirectReturnSlot(const AllocaInst &AI) {
+  bool FoundSRet = false;
+  SmallVector<const Instruction *, 8> Worklist = {&AI};
+  SmallPtrSet<const Instruction *, 8> Visited = {&AI};
+
+  while (!Worklist.empty()) {
+    for (const Use &U : Worklist.pop_back_val()->uses()) {
+      const auto *User = cast<Instruction>(U.getUser());
+
+      if (const auto *CB = dyn_cast<CallBase>(User)) {
+        const auto *II = dyn_cast<IntrinsicInst>(CB);
+        if (II && (II->isLifetimeStartOrEnd() || II->isAssumeLikeIntrinsic()))
+          continue;
+        // A memory intrinsic reads or writes through the pointer, just as a
+        // load or a store does, and does not let it escape.
+        if (isa_and_nonnull<MemIntrinsic>(II))
+          continue;
+        if (!CB->isArgOperand(&U) ||
+            !CB->paramHasAttr(CB->getArgOperandNo(&U), Attribute::StructRet))
----------------
efriedma-quic wrote:

We've been trying pretty hard to move away from using StructRet for anything 
other than modifying the ABI.  I'd rather not reverse that trend.

This heuristic also seems pretty dubious to me; it's easy to construct a buffer 
overflow on an sret value with NRVO.  For example, `struct S { int x[100]; }; S 
f(int n) { S s; s.x[n] = 10; return s; }`.

How important is this in terms of reducing the number of stack protectors?

https://github.com/llvm/llvm-project/pull/225626
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to