Skip to content

fix(initimg): keep glibc's reported main stack size near RLIMIT_STACK - #62

Merged
not-matthias merged 1 commit into
masterfrom
cod-4117-main-stack-reported-size
Nov 4, 2026
Merged

not-matthias merged 1 commit into
masterfrom
cod-4117-main-stack-reported-size

Conversation

@not-matthias

@not-matthias not-matthias commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

TLDR: Since #53 glibc reported a 4 KiB main thread stack at the default 8 MiB limit, which breaks CPython 3.14 (BufferError at startup). The startup strings now live in their own mapping so only 64 KiB sits above SP in the stack mapping; glibc reports RLIMIT_STACK - 64 KiB (native: - ~100 KiB), SP stays fixed.

Layout (initimg-linux.c)

  • pthread_getattr_np computes RLIMIT_STACK - (end of VMA containing SP - SP). The fixed 8 MiB region from fix(initimg): stabilize Linux startup stack layout #53 was all inside that VMA.
  • Strings grow up from a fixed strings_start in a separate anonymous mapping; argc/argv/envp/auxv tables (64 KiB granule) stay above SP. One reserved, unmapped page between the two keeps the kernel from merging the VMAs.
  • Tables larger than 64 KiB take whole granules from the string mapping, so SP never moves. Hard error only when tables + page + strings exceed 8 MiB, as before.
  • Reservation size szB + 8 MiB and growth-on-fault are unchanged.

m_main.c

  • Main thread client_stack_szB is now sized from the segment holding SP instead of clstack_max_size, so the overflow message and setrlimit comparison no longer include the string mapping.

Test

  • none/tests/linux/main_stack_attr: reported range must cover SP and be within 1 MiB of an 8 MiB limit; then re-execs itself with 20000 args under --trace-children=yes to cover the granule fallback. Fails on master (SP ... outside reported stack [.., ..+4 KiB)), passes natively.

Measured (8 MiB ulimit -s, x86_64)

case master this PR native
default env 4 KiB 8132 KiB 8096 KiB
600 KB env 4 KiB 8132 KiB, same SP
20000 args 4 KiB 8004 KiB, same SP
Python 3.14 under callgrind BufferError OK OK

none/tests/linux: 18/19 pass; getdents_filter fails on master too. memcheck/tests/linux: 27/28, sys-execveat fails on master too. memcheck, helgrind and drd run a program that reads all of argv[] and environ without reports.

Review notes

  • argv/envp strings are no longer inside the [stack] VMA. Visible only through /proc/self/maps; in-place argv rewriting still works (mapping is RW).
  • Pre-existing and unchanged: ulimit -s 64M reports 64 MiB while usable depth is clamped to 16 MiB; runtime setrlimit does not grow the reservation.

COD-4117

@not-matthias
not-matthias force-pushed the cod-4117-main-stack-reported-size branch 2 times, most recently from bcc5636 to efc8a0a Compare November 4, 2026 14:39
@codspeed

codspeed Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 84 untouched benchmarks
⏩ 60 skipped benchmarks1


Comparing cod-4117-main-stack-reported-size (ab3ed5c) with master (d034e80)

Open in CodSpeed

Footnotes

  1. 60 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@not-matthias
not-matthias marked this pull request as ready for review November 4, 2026 15:02
@greptile-apps

greptile-apps Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The change affects main-stack setup for Linux programs launched under Valgrind.

Fix the Darwin stack-size calculation before merging; it breaks DRD startup.

Fix All in Claude CodeFindings

  1. P1 DRD startup breaks on Darwin ▶
Fix with agent prompt
### Issue 1
coregrind/m_main.c:2167-2168
On Darwin, `am_startup` returns `(Addr)-1`, and `ii_create_image` replaces `clstack_end` only in its local copy. The global `the_iicii.clstack_end` stays at `(Addr)-1`, so this unsigned subtraction wraps `stack_szB` to `clstack_max_size + seg->end + 1`.

With DRD's default settings, that oversized value makes the stack suppression range start above its end. `start_suppression` then fails its assertion before client code runs. Apply this adjustment only on Linux, or return the actual stack top from `ii_create_image`.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Moves Linux startup strings into a separate mapping so glibc reports a main-thread stack size close to RLIMIT_STACK.

  • Linux programs get a main-thread stack report close to the stack limit.

Known and unchanged: not-matthias identified large inherited stack limits and runtime reservation growth as pre-existing limitations. not-matthias also explicitly noted that moving startup strings outside the stack mapping is intentional.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart BT
  R["Reserved space for stack growth"] --> S["Runtime stack below fixed SP"]
  S --> T["Startup pointer tables: 64 KiB granules"]
  T --> G["One reserved, unmapped page"]
  G --> A["Separate mapping for startup strings"]
Loading

Reviews (1) · Last reviewed commit: "fix(initimg): keep glibc's reported main..." · Reviewed by Greptile

Comment thread coregrind/m_main.c Resolved
@not-matthias
not-matthias force-pushed the cod-4117-main-stack-reported-size branch from efc8a0a to a67fed7 Compare November 4, 2026 15:10

@GuillaumeLagrange GuillaumeLagrange left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Comment thread CODSPEED-CHANGELOG.md Resolved
glibc's pthread_getattr_np computes the main thread's stack size as
RLIMIT_STACK minus the distance from __libc_stack_end to the end of the
mapping containing it. Since the fixed startup stack layout pinned SP
8 MiB below the top of that mapping, glibc subtracted the whole region
and reported a 4 KiB main stack at the default 8 MiB limit. CPython 3.14
derives its C-stack guard from that size and failed at startup with
BufferError.

Split the startup image in two mappings: the argv/env/auxv strings grow
upward from a fixed strings_start in their own anonymous mapping, and
only the pointer tables (64 KiB, TABLES_REGION_SZB) stay above SP in
the stack mapping. An unmapped, reserved page between them keeps the
kernel from merging the two VMAs. glibc now reports RLIMIT_STACK minus
64 KiB (natively about 100 KiB), while SP, strings_start and the
reservation bottom stay fixed for any argument and environment size.
Tables larger than one granule take whole granules from the string
mapping without moving SP.

The main thread's client_stack_szB is now derived from the segment that
holds SP instead of clstack_max_size, so the overflow message and the
setrlimit comparison no longer count the string mapping.

Add none/tests/linux/main_stack_attr, which checks that the reported
range covers SP and is within 1 MiB of RLIMIT_STACK, then re-executes
itself with 20000 arguments to exercise the table fallback under
--trace-children=yes. It fails on the previous layout and passes
natively.
@not-matthias
not-matthias force-pushed the cod-4117-main-stack-reported-size branch from a67fed7 to ab3ed5c Compare November 4, 2026 16:10
@not-matthias
not-matthias merged commit f2aa7a9 into master Nov 4, 2026
10 of 11 checks passed
@not-matthias
not-matthias deleted the cod-4117-main-stack-reported-size branch November 4, 2026 16:35
adriencaccia added a commit to CodSpeedHQ/codspeed that referenced this pull request Nov 9, 2026
Since 0codspeed12, glibc reported the main thread stack as 4 KiB under
valgrind at the default `ulimit -s`, so Python 3.14 failed at startup
with a BufferError. The new package reports a size close to RLIMIT_STACK
again (CodSpeedHQ/valgrind-codspeed#62).

Refs COD-4123

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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