llama: fix the qwen4exp PLE history seq_rm(-1) iterator invalidation and the fatal-warning build

ple_hist_rm recursed over ple_hist with a range-based for and the recursive call
erases the entry it is iterating when the whole sequence is removed (p0 <= 0,
p1 < 0), so the loop then increments an invalidated iterator. It is unreachable
today only because llama_memory_recurrent::seq_rm rejects seq_id < 0 before
llama_memory_hybrid_idx::seq_rm reaches the history, which is a guard in another
class. Advance past the entry before recursing.

Two smaller things in the same area:

  - the n_toks sanity bound in ple_hist_state_read was the literal 64, which is
    the value of LLAMA_MAX_PLE_HEADS, not of the quantity being checked. The
    window is at most ple_ngram_size - 1 tokens, so the bound is
    LLAMA_MAX_PLE_NGRAM - 1, eight times tighter.

  - build_conv_state_at left mem_size unused, so -DLLAMA_FATAL_WARNINGS=ON does
    not compile. Predates this series; drop the line.

(cherry picked from commit 6eba44a89d5f328eb4859b844e1d28fb564cbe3e)
This commit is contained in:
Daniel Han
2026-08-27 01:18:11 +00:00
parent 5674c73aa8
commit 24ea62df44
+9 -5
View File
@@ -249,8 +249,12 @@ static void ple_hist_truncate(llama_memory_hybrid_idx::ple_history & h, llama_po
void llama_memory_hybrid_idx::ple_hist_rm(llama_seq_id seq_id, llama_pos p0, llama_pos p1) {
if (seq_id < 0) {
for (auto & it : ple_hist) {
ple_hist_rm(it.first, p0, p1);
// the recursive call erases seq_id's entry when the whole sequence is removed, so
// advance past it first: erase invalidates only the iterator to the erased element
for (auto it = ple_hist.begin(); it != ple_hist.end(); ) {
const llama_seq_id id = it->first;
++it;
ple_hist_rm(id, p0, p1);
}
return;
}
@@ -433,9 +437,9 @@ void llama_memory_hybrid_idx::ple_hist_state_read(llama_io_read_i & io, llama_se
io.read(&next_pos, sizeof(next_pos));
io.read(&n_toks, sizeof(n_toks));
// the window is never longer than ple_ngram_size - 1, so a larger count is a corrupt
// blob and would size an allocation from the file
if (n_toks > 64) {
// the window is never longer than ple_ngram_size - 1; anything else is a corrupt or
// mismatched blob, and reading it would size an allocation from the file
if (n_toks > LLAMA_MAX_PLE_NGRAM - 1) {
throw std::runtime_error("qwen4exp PLE history: implausible token count in state blob");
}