Skip to content

AOT: fix multi-arg sprintf/printf segfault — bypass broken NestedJIT pack path - #32601

Merged
PurHur merged 1 commit into
masterfrom
agent/fix-sprintf-multi-arg-aot-segfault
Aug 19, 2026
Merged

PurHur merged 1 commit into
masterfrom
agent/fix-sprintf-multi-arg-aot-segfault

Conversation

@PurHur

@PurHur PurHur commented Aug 19, 2026

Copy link
Copy Markdown
Owner

Summary

  • Multi-arg sprintf("%d-%d", 3, 4) and printf("%s/%s", "a1", "b2") segfaulted in AOT because the NestedJIT pack path (phpc_pack_argv_serialize → SprintfJitHelper) returned null, causing echo of a null __string__* pointer (AOT: float→string conversion crashes — printf/number_format/json_encode/serialize/strval all segfault on floats #31963 class).
  • The single-arg fast path via libc snprintf (SprintfSnprintfRuntime::formatOneArg) worked correctly. This extends the same approach to multi-arg: at compile time we know the arg count and types, so JitSprintf::format() now emits a direct snprintf(buf, size, fmt, typed1, typed2, ...) call, extracting each arg as the correct C type (i64 for longs, double for floats, char* for strings).
  • JitPrintf::format() for multi-arg now delegates to JitSprintf::formatWithFmt() and echoes the result, instead of going through __compiler_printf's bridge.

Closes #31968 (child: multi-arg sprintf/printf)

Verification

  • aot-smoke: 8/8 (no regressions)
  • differential-sweep --aot: e05_sprintf.php now passes (was DIFF/segfault on master)
  • No new DIFF or COMPILE failures in sweep vs pre-change baseline
  • VM mode: sprintf("%d-%d", 3, 4) → 3-4 ✓ (unaffected, uses VmSprintf)

Not covered: full compliance suite (VMTest/JITTest), --strict self-host

Test plan

  • ./script/aot-smoke.sh — 8/8
  • ./script/differential-sweep.sh --aot — e05_sprintf fixed, no regressions
  • Repro: sprintf("%d-%d", 3, 4) → 3-4, printf("%s/%s\n", "a1", "b2") → a1/b2

Made with Cursor

…pack path

Multi-arg sprintf("%d-%d", 3, 4) and printf("%s/%s", "a1", "b2") segfaulted
in AOT because the NestedJIT pack path (phpc_pack_argv_serialize → SprintfJitHelper)
returned null, causing echo of a null __string__* pointer (#31963 class).

The single-arg fast path via libc snprintf (SprintfSnprintfRuntime::formatOneArg)
worked correctly. This extends the same approach to multi-arg: at compile time
we know the arg count and types, so JitSprintf::format() now emits a direct
snprintf(buf, size, fmt, typed1, typed2, ...) call, extracting each arg as the
correct C type (i64 for longs, double for floats, char* for strings).

JitPrintf::format() for multi-arg now delegates to JitSprintf::formatWithFmt()
and echoes the result, instead of going through __compiler_printf's bridge.

Verified:
- aot-smoke: 8/8 (no regressions)
- differential-sweep --aot: e05_sprintf.php now passes (was DIFF/segfault)
- No new failures in sweep vs pre-change baseline

Closes #31968 (child)

Co-authored-by: Cursor <cursoragent@cursor.com>
@PurHur
PurHur merged commit 05ce172 into master Aug 19, 2026
1 check failed
@PurHur
PurHur deleted the agent/fix-sprintf-multi-arg-aot-segfault branch August 19, 2026 11:05
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.

Tracking: AOT correctness inventory — 44 mismatches in 85 probes across two language areas

1 participant