Visitar URL original
fix(jolt-host): read the guest ELF once under a build lock by markosg04 · Pull Request #2121 · a16z/jolt · GitHub
Skip to content

fix(jolt-host): read the guest ELF once under a build lock - #2121

Merged
0xAndoroid merged 2 commits into
mainfrom
fix/guest-elf-race
Oct 26, 2026
Merged

0xAndoroid merged 2 commits into
mainfrom
fix/guest-elf-race

Conversation

@markosg04

Copy link
Copy Markdown
Collaborator

Tests that build the same guest in parallel intermittently panic with "Built ELF not found" or "ELF contents not available" (the ~2 s jolt-prover flakes). Every jolt build, even a no-op, has cargo delete and re-link the uplifted guest ELF, so any test reading the ELF by path while another test's build is in that window loses the race. The path is read in three places: the post-build existence check, built_elf, and get_elf_contents in build_jolt_program.

Program now holds a GuestElf (path plus Arc<[u8]> bytes) read once, right after the build, while an exclusive std::fs::File::lock on <guest_target_dir>/.jolt-build.lock is held from before jolt build until the read completes. Later consumers use the stored bytes; the path remains only for tracer panic symbolization.

Validation: with the race forced (concurrent builds of one guest), 20 of 80 runs failed on main and 0 of 80 with this change. Clippy (host), fmt, jolt-host tests and jolt-prover --features prover-fixtures (29/29) pass on the rebased head.

Every `jolt build`, even a no-op, has cargo delete and re-link the uplifted
guest ELF. Tests that build the same guest in parallel share one target
directory, so a test reading the ELF by path (the post-build existence check,
`built_elf`, and the later `get_elf_contents` in `build_jolt_program`) could
land in that window and panic with "Built ELF not found" or "ELF contents not
available".

`Program` now holds a `GuestElf` (path plus bytes) read once, right after the
build, while an exclusive lock on `<guest_target_dir>/.jolt-build.lock` is
held from before `jolt build` until the read completes. Every later consumer
uses the stored bytes; the path remains only for tracer panic symbolization.
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

📏 PR diff

Note

Actual code changed: 112 lines

🟢 +67 added    🔴 −45 removed

Tests, docs, fixtures, and helper scripts excluded.

Category 🟢 Added 🔴 Removed
⌨️ Actual code +67 −45
🧪 Tests +5 −3
📚 Docs +7 0
📦 Fixtures 0 0
🔧 Helper scripts 0 0
Total diff +79 −48

Every changed line is classified once.

@0xAndoroid

Copy link
Copy Markdown
Collaborator

@pika land

@0xandoroid-ai-agent 0xandoroid-ai-agent Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reviewed at b312c01. Taking the lock before jolt build and reading the ELF once under it is sound for Program builds; two inline items block landing: the red style check and the new clippy::panic suppression.

Not blocking: only Program::build_with_features takes .jolt-build.lock. The direct jolt build calls in tracer's test_utils::build_muldiv_guest, crates/jolt-tracer-x86/tests/common/mod.rs and tracer/examples/support/mod.rs write into the same jolt-guest-targets/{guest}-{func} directories without it, so they can still race with Program (this predates the PR).

Comment thread crates/jolt-host/src/lib.rs Outdated
}

impl GuestElf {
pub fn read(path: PathBuf) -> io::Result<Self> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

style fails on this line: [nominal-imports] import io::Result and use Result. A plain use std::io::Result would shadow the two-parameter Result that build_jolt_program returns below, so alias it the way jolt-sdk/src/host_utils.rs does: replace use std::io; with use std::io::Error as IoError; and return Result<Self, IoError>.

Comment thread crates/jolt-host/src/program.rs Outdated
#[expect(
clippy::expect_used,
reason = "the infallible host build API reports CLI failures by panicking"
clippy::panic,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

clippy::panic (denied workspace-wide) is added only for the panic! in the ELF read below. let elf = GuestElf::read(elf_path).expect("read the built guest ELF"); is already covered by this function's expect_used expectation, so the new suppression can go.

The style job rejects `io::Result` under the nominal-import rule, and a
plain `use std::io::Result` would shadow the two-parameter `Result` used
elsewhere in the file, so `GuestElf::read` returns `Result<Self, IoError>`.
The ELF read now uses `.expect`, already covered by the function's
`clippy::expect_used` expectation, so the added `clippy::panic` goes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@0xAndoroid
0xAndoroid merged commit a3a356c into main Oct 26, 2026
51 checks passed
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.

3 participants