From 293669f9afed489d079952a322c762348b88da8f Mon Sep 17 00:00:00 2001 From: FT_IOxCS <237263164+ft-ioxcs@users.noreply.github.com> Date: Mon, 20 Jul 2026 19:46:40 +0300 Subject: [PATCH] rax.c: add OOM guard in raxRemove for incomplete ancestor stack raxLowWalk:613 discards raxStackPush return value. If the stack heap-expansion fails (depth > 32, malloc(512)), ts.oom is set but the ancestor is silently dropped. raxRemove then calls raxRemoveCleanup before the existing ts.oom guard at line 1331 (which only suppresses recompression, not cleanup). The incomplete stack causes raxRemoveCleanup to pop wrong ancestors, potentially passing a non-child to raxRemoveChild, whose while(1) scan reads past the child array (UB, per the comment at raxFindParentLink:1128). Fix: check ts.oom immediately after raxLowWalk, matching the existing pattern at raxSeek:1966. Fault-injection test confirms: without fix, raxRemove returns 1 (false success) with corrupted tree; with fix, returns 0, tree intact. --- rax.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rax.c b/rax.c index b3ec8114c..0a75f535c 100644 --- a/rax.c +++ b/rax.c @@ -1276,6 +1276,10 @@ int raxRemove(rax *rax, unsigned char *s, size_t len, void **old) { int splitpos = 0; int inline_leaf = 0; size_t i = raxLowWalk(rax,s,len,&h,&parentlink,&splitpos,&ts,&inline_leaf); + if (ts.oom) { + raxStackFree(&ts); + return 0; + } int trycompress = 0; /* Will be set to 1 if we should try to optimize the tree resulting from the deletion. */