Skip to content

nvn/prebuild: write no archive period at exit in the bundle form - #2529

Open
hectorviov wants to merge 1 commit into
seedds:mainfrom
hectorviov:nvn-prebuild-exit-write
Open

hectorviov wants to merge 1 commit into
seedds:mainfrom
hectorviov:nvn-prebuild-exit-write

Conversation

@hectorviov

Copy link
Copy Markdown

Problem

On a Mac app build (--platform mac-app) of Ocarina of Time, the new prewarm step finished all its work and then failed:

[RED] prewarm pipelines: the host's prebuild tool failed (see .../logs/pso_prewarm_mac.log); the app is packed without them and builds them on its first start

The tool's own log ended at pipeline prebuild: 4 files (501.2 MB) for the app to bundle in ... with 0 failed, so the files were complete, but the tool ended by SIGTRAP, mac_prebake took the status for a failure and removed them.

Cause

Crash report (EXC_BREAKPOINT, macOS 27.3, M5 Pro): the main thread is in mtl_arch_save under exit() → __cxa_finalize_ranges, and the dm.nvn.pso-archive thread is in localeconv_l ← strtod_l ← libllvm-flatbuffers ← -[_MTL4PipelineDataSetSerializer serializeAsPipelinesScriptWithError:] ← prewarm_script ← arch_write_file.

After pre_bundle_out, a few captures were still pending (a task / mesh pipeline captured after the lists' last flush). The at-exit save (arch_at_exit → mtl_arch_save) handed them over as one more period. In the bundle form every period is also written as a pipelines script, which Metal's serializer parses with libllvm-flatbuffers' locale: a function-local static first made at the first script, after arch_at_exit was registered, so exit() has destroyed it by the time the handler runs. That is a read of freed memory: it trapped when the heap had reused it, and did not in two reruns of the same inputs (exit status 0, the same extra period written at exit).

Change

  • The tool waits for one more flush before pre_bundle_out (arch_flush_wait), so the bundle holds everything captured.
  • mtl_arch_save writes nothing at exit for the bundle form (ending && g_pre_out): a period captured after the bundle is made is bundled by nobody, and its script is the call that is not safe during exit.
  • A run that is not the bundle form writes no scripts and is unchanged.

New reference entry in docs/reference/shaders.md, a line in Ocarina of Time's note, symptom index regenerated.

Checked

On an M5 Pro, macOS 27.3: the host builds. The tool rerun on the failed build's captures with the patched host wrote the extra period before the bundle (6 files, 502.7 MB) and nothing after the bundle line, exit status 0. t_pso_bundle: 75 checks, 0 failed (it does not run the tool's exit). test_docs.

Not run

  • A rerun that reproduces the trap: it depends on the heap, and two reruns before the change did not trap.
  • lint_c.py tidy (no compile database in the checkout I used).
  • regress.py: the change is in the tool's bundle form only (DM_PSO_PREBUILD_OUT), which no game run uses.
  • The iPhone.

🤖 Generated with Claude Code

The Mac app build packed Ocarina of Time without its prewarm files after the
host's prebuild tool had made them all: the tool's log ended at "4 files
(501.2 MB) for the app to bundle ... 0 failed", yet the tool ended by
SIGTRAP, mac_prebake took the status for a failure and removed the complete
files ("[RED] prewarm pipelines: the host's prebuild tool failed ...").

The crash report: main thread in mtl_arch_save under exit() ->
__cxa_finalize_ranges, and the dm.nvn.pso-archive thread in localeconv_l <-
strtod_l <- libllvm-flatbuffers <- -[_MTL4PipelineDataSetSerializer
serializeAsPipelinesScriptWithError:] <- prewarm_script <- arch_write_file
(EXC_BREAKPOINT, macOS 27.3, M5 Pro). After pre_bundle_out, a few captures
were still pending (a task / mesh pipeline captured after the lists' last
flush), and the at-exit save (arch_at_exit -> mtl_arch_save) handed them over
as one more period. In the bundle form every period is also written as a
pipelines script, which Metal's serializer parses with libllvm-flatbuffers'
locale: a function-local static first made at the first script, after
arch_at_exit was registered, so exit() has already destroyed it when the
handler runs. A read of freed memory: it trapped when the heap had reused it,
and did not in two reruns of the same inputs (exit status 0, the same extra
period written at exit).

Now the tool waits for one more flush before pre_bundle_out
(arch_flush_wait), so the bundle holds everything captured, and
mtl_arch_save writes nothing at exit for the bundle form (ending &&
g_pre_out): a period captured after the bundle is made is bundled by nobody,
and its script is the call that is not safe during exit. A run that is not the
bundle form writes no scripts and is unchanged. New reference entry (The
prebuild tool trapped at exit and the app was packed without its prewarm
files), a line in Ocarina of Time's note, symptom index regenerated.

Checked on the M5 Pro (macOS 27.3): the host built; the tool rerun on the
failed build's captures with the patched host wrote the extra period before
the bundle (6 files, 502.7 MB) and nothing after the bundle line, exit status
0; t_pso_bundle 75 checks, 0 failed (it does not run the tool's exit);
test_docs. Not run: a rerun that reproduces the trap (it depends on the
heap; two reruns before the change did not trap), lint_c.py tidy (no compile
database in this checkout), regress.py (the change is in the tool's bundle
form only, DM_PSO_PREBUILD_OUT, which no game run uses), the iPhone.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added nvn NVN on Metal and its tests (dm/gfx/nvn, dm/gfx/tests) docs Documentation game: 0400486024DEC000 A game labels Nov 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Documentation game: 0400486024DEC000 A game nvn NVN on Metal and its tests (dm/gfx/nvn, dm/gfx/tests)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants