Name and Version
$./llama-completion --version
version: 0.4.1-dev (build 1617, commit 41abbfd)
built with AppleClang 21.0.0.21000101 for Darwin arm64
Operating systems
Mac
Which llama.cpp modules do you know to be affected?
Documentation/Github, libllama (core library)
Command line
Problem description & steps to reproduce
include/llama.h:248 says the arrays in llama_batch must have size n_tokens. For an M-RoPE model with an embeddings batch, pos is read at 4 * n_tokens. Nothing checks the length, and llama_batch_init allocates n_tokens.
I read this at commit 41abbfd59.
src/llama-hparams.cpp:286 returns 4 from n_pos_per_embd() for LLAMA_ROPE_TYPE_MROPE and LLAMA_ROPE_TYPE_IMROPE. Qwen2.5-VL and Qwen2.5-Omni use those.
src/llama-batch.cpp:786, in llama_batch_allocr::ubatch_add, reads the caller's array:
size_t src_off = batch.token ? 0 : j*batch.n_tokens;
udata->pos[j*n_tokens + i] = batch.pos[src_off + idxs[i]];
j runs to n_pos_per_embd. An embeddings batch has batch.token == NULL, so src_off reaches 3*batch.n_tokens. The highest index read is 4*batch.n_tokens - 1. The documented array holds batch.n_tokens entries.
Two cases hit this.
-
A caller that allocates the documented size. llama_batch_init at src/llama-batch.cpp:962 mallocs sizeof(llama_pos) * n_tokens_alloc. Use that batch for an M-RoPE embeddings prefill and the loop reads 3 * n_tokens positions past the end of the block.
-
A caller that passes pos = NULL. include/llama.h:253 says the position is then tracked automatically. src/llama-batch.cpp:91 resizes the internal vector to batch.n_tokens, and line 117 points batch.pos at it. The same loop reads past the end of llama.cpp's own vector. This case needs no caller mistake at all.
llama.cpp's own multimodal helper avoids both. tools/mtmd/mtmd-helper-common.h:85 sizes pos at n_tokens * n_pos_per_embd, while n_seq_id, seq_ids and logits stay at n_tokens. So the 4x requirement is known. It is met by hand in one helper, and it is not stated in the public header.
The read is silent. The extra positions are whatever follows the allocation. A run can stay coherent or drift, depending on what sits next to it on the heap. I think this is the cause of #28441.
What I suggest:
- State the requirement on
llama_batch in include/llama.h: pos must hold n_tokens * n_pos_per_embd entries.
- Size the fallback vector at
src/llama-batch.cpp:91 to batch.n_tokens * n_pos_per_embd and fill every section.
- Give
llama_batch_init a way to allocate the larger array. It takes no llama_model, so it needs the count as a parameter or a new entry point.
- Reject a batch that cannot meet the requirement, instead of reading past the end.
I found this by reading the code, not from a crash. I have no M-RoPE model on this machine to run under ASan, so I have not measured the overread at runtime.
First Bad Commit
No response
Relevant log output
No response
Name and Version
$./llama-completion --version
version: 0.4.1-dev (build 1617, commit 41abbfd)
built with AppleClang 21.0.0.21000101 for Darwin arm64
Operating systems
Mac
Which llama.cpp modules do you know to be affected?
Documentation/Github, libllama (core library)
Command line
Problem description & steps to reproduce
include/llama.h:248says the arrays inllama_batchmust have sizen_tokens. For an M-RoPE model with an embeddings batch,posis read at4 * n_tokens. Nothing checks the length, andllama_batch_initallocatesn_tokens.I read this at commit
41abbfd59.src/llama-hparams.cpp:286returns 4 fromn_pos_per_embd()forLLAMA_ROPE_TYPE_MROPEandLLAMA_ROPE_TYPE_IMROPE. Qwen2.5-VL and Qwen2.5-Omni use those.src/llama-batch.cpp:786, inllama_batch_allocr::ubatch_add, reads the caller's array:jruns ton_pos_per_embd. An embeddings batch hasbatch.token == NULL, sosrc_offreaches3*batch.n_tokens. The highest index read is4*batch.n_tokens - 1. The documented array holdsbatch.n_tokensentries.Two cases hit this.
A caller that allocates the documented size.
llama_batch_initatsrc/llama-batch.cpp:962mallocssizeof(llama_pos) * n_tokens_alloc. Use that batch for an M-RoPE embeddings prefill and the loop reads3 * n_tokenspositions past the end of the block.A caller that passes
pos = NULL.include/llama.h:253says the position is then tracked automatically.src/llama-batch.cpp:91resizes the internal vector tobatch.n_tokens, and line 117 pointsbatch.posat it. The same loop reads past the end of llama.cpp's own vector. This case needs no caller mistake at all.llama.cpp's own multimodal helper avoids both.
tools/mtmd/mtmd-helper-common.h:85sizesposatn_tokens * n_pos_per_embd, whilen_seq_id,seq_idsandlogitsstay atn_tokens. So the 4x requirement is known. It is met by hand in one helper, and it is not stated in the public header.The read is silent. The extra positions are whatever follows the allocation. A run can stay coherent or drift, depending on what sits next to it on the heap. I think this is the cause of #28441.
What I suggest:
llama_batchininclude/llama.h:posmust holdn_tokens * n_pos_per_embdentries.src/llama-batch.cpp:91tobatch.n_tokens * n_pos_per_embdand fill every section.llama_batch_inita way to allocate the larger array. It takes nollama_model, so it needs the count as a parameter or a new entry point.I found this by reading the code, not from a crash. I have no M-RoPE model on this machine to run under ASan, so I have not measured the overread at runtime.
First Bad Commit
No response
Relevant log output
No response