Skip to content

Carry patches/0020: ggml-alloc validates the leafs before reusing an allocation (fixes the --embedding crash) - #541

Merged
bernardladenthin merged 2 commits into
mainfrom
claude/sharp-davinci-enu4pk
Oct 15, 2026
Merged

bernardladenthin merged 2 commits into
mainfrom
claude/sharp-davinci-enu4pk

Conversation

@bernardladenthin

Copy link
Copy Markdown
Owner

Summary

  • The crash: In the Publish dispatch on the Upgrade llama.cpp from b11632 to b11639 and install oneDNN for the Linux SYCL module #539 merge (run 38648257387, the first run since b11558 to reach the Java tests), ErrorHandlingTest killed the fork in four Java test jobs: SIGSEGV on Ubuntu and on macOS 26, 0xC0000005 under both Windows toolchains, each time in ggml_gallocr_alloc_graph. On macOS si_addr was 0xfffffffffffffff8, which is galloc->buffers[-1]. The test loads its model with enableEmbedding(), and its first test sends that model an infill request. The stack is server_context_impl::update_slots → llama_context::decode → process_ubatch → ggml_backend_sched_alloc_graph → ggml_gallocr_alloc_graph.
  • Cause (upstream, b11574..b11612, so not introduced by Upgrade llama.cpp from b11632 to b11639 and install oneDNN for the Linux SYCL module #539): graph: skip the LM head for pooled embeddings ggml-org/llama.cpp#30445 (cb55ffe6e, "graph: skip the LM head for pooled embeddings") now expands the LM head in build_logits(), after build_pooling().
    • An embeddings context therefore reserves a graph that expands t_embd first and t_logits second. A generation step on the same context expands only t_logits, whose first source is output.weight.
    • Both graphs have the same nodes and the same leaf count, but the leafs are shifted by one.
    • ggml_gallocr_needs_realloc() validates the nodes and their sources, but compares the leafs only by count. So the input leaf out_ids got the slot of a weight (buffer_id -1).
  • Fix: patches/0020. It validates the leafs the same way the nodes are validated. With one buffer, an invalid leaf makes the allocator reserve again; otherwise it returns false and ggml_backend_sched reserves the graph itself. Upstream master (a0e6dc738) still lacks the check. Not yet filed upstream.
  • Guard: test_gallocr_leafs.cpp. Two graphs whose nodes and node sources match and in which only the leafs move.

Test plan

  • Reproduced locally without a downloaded model, using a random 2-layer llama GGUF with FIM tokens and a context of 128: infill crashes with --embedding and works without. A debug print showed out_ids arriving at a slot with no allocation.
  • Reverting cb55ffe6e makes the reproduction pass. So does this patch on its own: with greedy sampling (temperature 0), the --embedding model returns the same tokens as the model without it, on repeated runs.
  • Fresh build through the production path (FetchContent by commit, all 13 patches, pin check 11639 = b11639): ctest 602/602.
  • The guard fails without the fix (SIGSEGV, rc 139) and passes with it. A first version that swapped the operands of one add passed without the fix, because a moved node source was already caught; the final guard moves only the leafs.
  • ErrorHandlingTest against the tiny model, 16/16; model-free native Java tests 27/27.
  • check-patches (13 patches, 95 hunks, 0 problems), check-natives, clang-format 23.1.3.
  • CI: the model-backed Java suite on every platform.

Also red in 38648257387: Build and Test macOS 15 arm64 (no Metal). That is not a code problem: cloning BoringSSL failed with HTTP 503 from boringssl.googlesource.com.

Related issues / PRs

Follows #539 (b11639). Upstream cause: ggml-org/llama.cpp#30445.

Checklist

  • I have read CONTRIBUTING.md and CODE_OF_CONDUCT.md
  • My commits follow Conventional Commits (they follow this repo's own message style)
  • No security-sensitive changes

🤖 Generated with Claude Code

https://claude.ai/code/session_01DdW3CyYtKkK6BQ3VGARo2E


Generated by Claude Code

…location

The first full Publish run since b11558 (38648257387, on the b11639 merge)
crashed ErrorHandlingTest in all three Java test jobs: SIGSEGV in
ggml_gallocr_alloc_graph on Linux, 0xC0000005 with both Windows
toolchains. The test loads its model with enableEmbedding() and posts an
infill request to it.

Cause, upstream since #30445 (cb55ffe6e, b11574..b11612): the LM head is
expanded by build_logits() after build_pooling(), so an embeddings
context reserves a graph expanding t_embd then t_logits, while a
generation step on it expands only t_logits, whose first source is
output.weight. Same node and leaf counts, the leafs shifted by one.
ggml_gallocr_needs_realloc() validates nodes and their sources but of
the leafs only the count, so the input leaf out_ids received the slot of
a weight (buffer_id -1) and ggml_vbuffer_tensor_alloc() indexed
galloc->buffers[-1].

Reproduced without a downloaded model (random 2-layer llama GGUF with
FIM tokens, context 128): infill crashes with --embedding and works
without; reverting cb55ffe6e passes, and so does validating the leafs
like the nodes. With the patch greedy infill on the --embedding model
returns the same tokens as without. Guard: test_gallocr_leafs.cpp, two
graphs with the same counts and the leafs swapped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdW3CyYtKkK6BQ3VGARo2E
The first version of test_gallocr_leafs.cpp swapped the operands of one
add, which moves a node source too -- the check that existed before the
patch already caught that, so the test passed without the fix. The guard
now keeps both nodes and their sources in place and moves only the leafs,
the shape of the llama.cpp case: it dies with SIGSEGV without the patch
and passes with it (602/602).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdW3CyYtKkK6BQ3VGARo2E

Copy link
Copy Markdown
Owner Author

The two red "Verify GPG signing key" checks do not come from this PR.

Both jobs run with environment: maven-central. On a branch other than main they end after 2 s without running a single step, so they fail before the signing self-test even starts. The same happened on #539 and #538 (see the comment on #539). On the main dispatch, 38648257387, both jobs ran green.

This PR does not touch either job or verify-signing-key.sh, so there is nothing to port. A re-run would fail the same way. The checks that matter for this change, the model-backed Java tests, only run in a Publish dispatch, either on this branch or after the merge.


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

claude-review is red, but not because of this PR.

The review action quit 294 ms after it started, with "is_error": true, "total_cost_usd": 0 and an empty modelUsage (run 38655827604). So the model never received a turn, and no comment was posted. That is a failure in the review action's call to the API, for example the key or the account behind it, not a review finding.

There is nothing in this diff to fix for it. A re-run makes sense once the action can reach the API again.


Generated by Claude Code

@sonarqubecloud

Copy link
Copy Markdown

@bernardladenthin
bernardladenthin merged commit 85cda4f into main Oct 15, 2026
81 of 85 checks passed
@bernardladenthin
bernardladenthin deleted the claude/sharp-davinci-enu4pk branch October 15, 2026 19:39

This branch had an error being deployed

1 failed and 1 active deployments
startgate — 1918d6a7 Deployed Oct 14, 2026 by bernardladenthin via Start gate (abort window) #1263
maven-central — 1918d6a7 Deployed Oct 14, 2026 by bernardladenthin via Verify GPG signing key (no secrets printed) #1263
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