Skip to content

[IR] Add the "zeroize-stack" function attribute - #1

Open
claude[bot] wants to merge 1 commit into
enforced_secrecy_mainfrom
zeroize-stack-attribute
Open

[IR] Add the "zeroize-stack" function attribute#1
claude[bot] wants to merge 1 commit into
enforced_secrecy_mainfrom
zeroize-stack-attribute

Conversation

@claude

@claude claude Bot commented Aug 11, 2026

Copy link
Copy Markdown

Requested by Francesco Bertolaccini · Slack thread

Define a string function attribute requesting that a function clear its stack
frame before returning, so that data the frame held is not left readable to
whatever runs on those addresses next. The attribute takes a required mode:
"used" clears every stack slot the function used, and "sensitive" clears the
slots that sensitivity metadata identifies plus every slot whose contents cannot
be traced back to a source-level object. The second half of "sensitive" is not
optional: spill slots, the callee-save area and alignment padding can all hold
copies of marked data, and nothing records where those copies came from.

The fallback between the two modes is deliberately one-directional. Passes are
free to drop sensitivity metadata, and once it is gone the remaining obligation
is "used", so losing the metadata only ever widens what gets cleared and never
narrows it. An unrecognized mode value is treated as "used" for the same
reason.

No consumer reads the attribute yet, and it needs no parser or printer code:
parsing and printing are generic for string function attributes, so
llvm/test/Assembler/zeroize-stack.ll covers the textual and bitcode
round-trips on its own. "zero-call-used-regs" is modelled the same way — it
appears in no parser, printer or attribute-definition file, and is decoded on
demand at its single consumption site in PrologEpilogInserter.cpp via a
StringSwitch — and it gains its mode enum in the same patch as that consumer.
Adding one here ahead of a consumer would be unused code.

How the attribute constrains inlining is left to
trailofbits/vspells-ct-internal-notes#14; the LangRef entry states the invariant
a transform must preserve and defers the inlining rule rather than asserting
one. That change needs to land before any backend consumer of this attribute:
until it does, the inliner will fold a "zeroize-stack" callee into an
unprotected caller and drop the obligation silently, which is inert while
nothing reads the attribute and becomes a miscompile the moment something does.

The names here are recommendations still awaiting sign-off on
trailofbits/vspells-ct-internal-notes#64. Nothing in this change makes a rename
hard: the attribute string appears only in the LangRef entry and the test.

Closes trailofbits/vspells-ct-internal-notes#9.

AI tool use

This pull request contains AI-generated content. It was prepared with the assistance of Claude Code; the contributor has reviewed the generated code and text, is the author of the contribution, and is accountable for it, per the LLVM AI Tool Use Policy.


Generated by Claude Code

Define a string function attribute requesting that a function clear its
stack frame before returning, so that data the frame held is not left
readable to whatever runs on those addresses next. The attribute takes a
required mode: "used" clears every stack slot the function used, and
"sensitive" clears the slots that sensitivity metadata identifies plus
every slot whose contents cannot be traced back to a source-level
object.

The fallback between the two modes is deliberately one-directional.
Passes are free to drop sensitivity metadata, and once it is gone the
remaining obligation is "used", so losing the metadata only ever widens
what gets cleared and never narrows it. An unrecognized mode value is
treated as "used" for the same reason.

No consumer reads the attribute yet. Parsing and printing are generic
for string function attributes, so the round-trip test covers them
without any new parser code. How the attribute constrains inlining is
left to a later change.

The names are recommendations still awaiting sign-off on
trailofbits/vspells-ct-internal-notes#64.
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@claude
claude Bot force-pushed the zeroize-stack-attribute branch from 66b3ca1 to a50c171 Compare August 11, 2026 16:33
@claude claude Bot changed the title Document the zeroize-stack function attribute [IR] Add the "zeroize-stack" function attribute Aug 11, 2026
kumarak added a commit that referenced this pull request Aug 11, 2026
Emit the two IR function attributes a protected function needs:
"zero-call-used-regs"="all" for register clearing and the new
"zeroize-stack"="used" for stack clearing. The register attribute is the
existing one, reused unchanged. Pinning it to "all" rather than one of the
"used" modes is deliberate: the used-register computation ignores implicit
operands and so misses registers defined only implicitly, which is
acceptable for a hardening option and not for an obligation over machine
state.

The lowering runs after the zero_call_used_regs block so that it wins over
both the command-line mode and an explicit zero_call_used_regs on the same
function. The attribute's guarantee is a minimum that other policy may
widen but not narrow.

Unlike zero_call_used_regs, the requests are not stamped onto call sites.
They describe the callee's own frame and its exits, and putting them on a
call instruction would suggest the call site clears something.

An explicitly annotated main keeps both requests. The existing exemption
that strips the command-line default from main is narrowed rather than
removed, so an un-annotated main is unaffected.

ClangIR emits the same requests, which needs a zeroize_stack field on
LLVM::LLVMFuncOp and the underscore-to-dash conversion in the MLIR
translator. -fzero-call-used-regs behaviour is unchanged throughout, which
the existing zero-call-used-regs tests pin.

Part of #1. Closes #3.
@kumarak
kumarak marked this pull request as ready for review August 11, 2026 23:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants