Skip to content

Misc. bug: M-RoPE embedding batches read batch.pos past the end of the documented n_tokens array #28902

Description

@devYRPauli

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.

  1. 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.

  2. 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions