40288931d6f7e083f7b71fd97109c03d9916bc30 jcasper Thu Aug 27 09:30:25 2026 -0700 When memalloc fails, it calls errAbort. But if the handler is a sophisticated one, it might try to call memalloc itself, resulting in an endless loop. Better to nip that in the bud. no ticket diff --git src/lib/memalloc.c src/lib/memalloc.c index 3ff198f1793..17d474db5c3 100644 --- src/lib/memalloc.c +++ src/lib/memalloc.c @@ -1,30 +1,31 @@ /* memalloc.c - Routines to allocate and deallocate dynamic memory. * This lets you have a stack of memory handlers. The default * memory handler is a thin shell around malloc/free. You can * substitute routines that do more integrety checking with * pushCarefulMem(), or routines of your own devising with * pushMemHandler(). * * This file is copyright 2002 Jim Kent, but license is hereby * granted for all use - public, private or commercial. */ #include #include "common.h" #include "obscure.h" #include "memalloc.h" #include "dlist.h" +#include "errAbort.h" static size_t memAlloced = 0; size_t memCheckPoint() /* Return the amount of memory allocated since last called. */ { size_t ret = memAlloced; memAlloced = 0; return ret; } static void *defaultAlloc(size_t size) @@ -192,32 +193,42 @@ #define NEEDMEM_LIMIT 500000000 void *needMem(size_t size) /* Need mem calls abort if the memory allocation fails. The memory * is initialized to zero. */ { void *pt; if (size >= 0x8000000000000000) // caused by overflowed signed int getting sign-extended size += 4294967296; if (size == 0 || size > NEEDMEM_LIMIT) errAbort("needMem: trying to allocate %llu bytes (limit: %llu)", (unsigned long long)size, (unsigned long long)NEEDMEM_LIMIT); if ((pt = mhStack->alloc(size)) == NULL) + { + if (isErrAbortInProgress()) + { + /* Calling errAbort here would re-enter the warn handler and loop. + * dumpStack makes no heap allocations (fork+pstack) and has its own + * re-entrancy guard; exit immediately after. */ + dumpStack("needMem: out of memory during error handling"); + exit(1); + } errAbort("needMem: Out of memory - request size %llu bytes, errno: %d\n", (unsigned long long)size, errno); + } memset(pt, 0, size); memAlloced += size; return pt; } void *needMoreMem(void *old, size_t oldSize, size_t newSize) /* Adjust memory size on a block, possibly relocating it. If vp is NULL, a * new memory block is allocated. No checking on size. If block is grown, * new memory is zeroed. */ { return needLargeZeroedMemResize(old, oldSize, newSize); } void *wantMem(size_t size) /* Want mem just calls malloc - no zeroing of memory, no