From d439ac8680e0169ff7c83f2f5538bed5a9bcf1f4 Mon Sep 17 00:00:00 2001 From: Dennis Paul Date: Mon, 13 Jul 2026 19:42:24 +0200 Subject: [PATCH] =?UTF-8?q?attention:=20size=20per-thread=20score=20buffer?= =?UTF-8?q?=20by=20the=20batch's=20true=20max=20nt,=20not=20Tk+1=20?= =?UTF-8?q?=E2=80=94=20fixes=20serve=20heap-overflow=20(#117)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit step_decode_batch (run_serve_mux) passes per-slot positions[]/kv_start, so nt=pos+1-st0 can exceed the old Tk+1 cap -> heap-buffer-overflow on the first serve request (ASan-confirmed, dnnspaul). sc_cap now = max nt over the batch, counted exactly as the write loop (per-slot positions/kv_start + DSA top-k). Non-batched paths reduce to the correct cap (MTP kv_start=-1 -> Tk+1). Validated: make check 58/58, oracle 32/32 TF, build 0-warning; real-model serve completes with ASan clean. --- c/glm.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/c/glm.c b/c/glm.c index 35d6dbd..bce736e 100644 --- a/c/glm.c +++ b/c/glm.c @@ -1581,9 +1581,20 @@ static void attention_rows(Model *m, Layer *l, int layer, float *x, int S, int p if(absorb && c->kv_lora<=512){ m->t_aproj+=now_s()-ta0; double tac=now_s(); int kvl=c->kv_lora, r0v=c->qk_nope; /* offset righe V dentro il blocco di testa */ - /* punteggi per-thread sul HEAP (vedi dev): cap Tk+1 copre anche il kv_start - * per-slot del percorso kvs (MTP: kv_start=-1 -> nt=Tk+1). */ - int64_t sc_cap = (int64_t)Tk+1; + /* Punteggi per-thread sul HEAP. Il cap DEVE essere il massimo nt effettivo del + * batch, non Tk+1: Tk=pos_base+S vale solo quando pos==pos_base+s. Il percorso + * batched (step_decode_batch da run_serve_mux) passa positions[] e kv_start + * per-slot, quindi nt=pos+1-st0 puo' superare Tk+1 -> heap-buffer-overflow su + * sc[jj]. Si conta esattamente come il loop sotto. */ + int64_t sc_cap = 1; + for(int s=0;skv; + int pos=positions?positions[s]:pos_base+s; + int st0=ks->kv_start[layer]; + int ns=(dnsel && dnsel[s]>0)?dnsel[s]:0; /* DSA: top-k, altrimenti range pieno */ + int64_t nt = ns ? (int64_t)ns : (int64_t)pos+1-st0; + if(nt>sc_cap) sc_cap=nt; + } float *sc_all = falloc((int64_t)omp_get_max_threads()*sc_cap); int cuda_core=0; #ifdef COLI_CUDA