Skip to content

self: ended include blocks, scoped-block self, module self export (0207) - #551

Merged
rmorozov merged 3 commits into
masterfrom
claude/project-thread-dkg9rb
Oct 17, 2026
Merged

rmorozov merged 3 commits into
masterfrom
claude/project-thread-dkg9rb

Conversation

@rmorozov

Copy link
Copy Markdown
Member

Requested by Ruslan · project thread

Before: a self stored by an include and called after the include ended rendered the caller's block of that name (OB), and a stored super read a dead stack (ASan stack-use-after-return, Debug segfault). self.c() from a scoped block in a loop rendered c without the loop variable. {% import 'm' as l %}{{ l.self }} was empty for a module that sets self, and self is iterable was False.

After: all of these match Jinja2 3.1.6. The stored self renders the include's blocks (IB), including self and super() inside them. A scoped block passes the names it sees to the blocks its self renders, scoped or not. Modules export a top-level self, and self is iterable is True.

How: BlocksStack gets a shared SelfBlocks holder, created with the first self or super made of it. When the stack ends, its destructor moves its blocks into the holder. The self and super callables hold the holder (shared ownership, no raw stack pointer), so they compare frames against the live stack and render the ended blocks once it is gone; this also closes the address-reuse hazard of the old pointer compare. RenderContext::FindSelf builds a self at the scoped block's depth when the block sees more than its template's top level. It is cached per block call in a new m_blockSelf of the block's context. ImportNames no longer skips self, which was a leftover from when self lived in the scope.

Corpus: three lines of task 0207 removed from divergences/loader.txt, plus 19 new cases in cases/loader.py. Two cases are pinned as deliberate under 0165, the same choice as for macros: a self kept past its include does not keep the include's names, and one kept past its scoped block loses the loop variable. Two more are pinned under the new task 0211, a quirk where Jinja2's block reads the top-level self when the block stores self only in a nested scope. 0211 also lists the verifier's pre-existing findings: parent-only blocks are missing from a top-level self in an extending template, an extending module does not export self, and cycler is iterable.

Perf: preflight.sh --perf stays within +0.4% on every benchmark. The scoped-in-loop pattern now builds one self per block call that uses it; before this change that pattern rendered the wrong output.

Roles: main session implemented; verifier ran for 1 round, finding 1 blocking issue (self undefined inside a block rendered through an ended self) and the pre-existing stored-super UAF. Both are fixed in f330e4d and covered by corpus rows. Then ASan+UBSan (clang 18) on the full suite came back clean. Red pushes: none yet.


Generated by Claude Code

…(0207)

A stack hands its blocks to the self made of them when it ends, so a
self an include stored renders the include's blocks. A scoped block that
sees more than its template's top level gets a self of what it sees, as
Jinja2's TemplateReference of the block's derived context. Modules export
a top-level self, and self is iterable. Leftovers filed as 0209.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TtbXoDehzWkexrJD9ZEBiK
…0207)

A block rendered through an ended self resolves self to the ended
blocks, and super() holds the stack's SelfBlocks instead of a raw
pointer, so one stored past an include no longer reads a dead stack.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TtbXoDehzWkexrJD9ZEBiK
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TtbXoDehzWkexrJD9ZEBiK
@rmorozov rmorozov self-assigned this Oct 17, 2026
@rmorozov
rmorozov marked this pull request as ready for review October 17, 2026 17:41
@rmorozov
rmorozov merged commit 1b9458b into master Oct 17, 2026
41 checks passed
rmorozov added a commit that referenced this pull request Oct 17, 2026
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