From 2bdf05462215d8a4591cc47520c2a9cef6e550f5 Mon Sep 17 00:00:00 2001 From: Michael Denyer Date: Wed, 15 Jul 2026 00:33:45 +0100 Subject: [PATCH] glm: fix kv_alloc double-free on KV re-allocation (stale pre-Metal free block) kv_alloc had two consecutive if(k->Lc) free blocks. The first freed every k->Lc[i]/k->Rc[i] and both arrays without unregistering from Metal and without nulling k->Lc; the second then re-tested the dangling pointer, called coli_metal_unregister on freed pointers, and freed everything a second time. Safe only when k->Lc is NULL (first call); any re-allocation on the same KVState aborts in the allocator. The first block is the pre-Metal version of the free path: 3716e40 (Metal backend) replaced it with the Metal-aware block, and ec89136 (GPU resident pipeline) re-added it above during the merge. Delete it so the Metal-aware block is the only free path. Caught by tests/test_kv_alloc from the previous commit: before: malloc: *** error for object 0x7: pointer being freed was not allocated (exit 134) after: OK kv_alloc re-allocation (exit 0) --- c/glm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/c/glm.c b/c/glm.c index 8da3f55..6b3b140 100644 --- a/c/glm.c +++ b/c/glm.c @@ -3066,7 +3066,6 @@ static void kv_alloc(Model *m, int max_t){ m->kv_dev_valid[i]=0; } #endif - if(k->Lc){ for(int i=0;in_layers+1;i++){ free(k->Lc[i]); free(k->Rc[i]); } free(k->Lc); free(k->Rc); } if(k->Lc){ for(int i=0;in_layers+1;i++){ #ifdef COLI_METAL if(g_metal_enabled){ coli_metal_unregister(k->Lc[i]); coli_metal_unregister(k->Rc[i]); }