Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit b62fad6

Browse files
committed
[Bug 18925] libfoundation: Prevent stack overflow on 2+ OOMs
The stack trace attached to bug 18925 shows the following calls occurring recursively until stack overflow: ... MCMemoryNew() __MCValueCreate() MCErrorCreateWithMessage() MCErrorThrowOutOfMemory() MCMemoryNew() ... `MCInitialize()` allocates the error structure for use during OOM into a global. Originally, `MCErrorThrowOutOfMemory()` did two things that seemed sensible: - if there was no OOM error structure, it would attempt to create one, and if that failed, it would exit - after using the global OOM structure, it would clear it Unfortunately, this meant that the first OOM that occurred during each run would be fine -- because there would be a preallocated OOM error structure -- but on second and subsequent OOM events, the global structure would be nil. Attempting to allocate the error would cause a recursive invocation of `MCMemoryNew()`, which would fail and attempt to throw an OOM error, which would try to allocate an error, etc. This patch ensures that `MCErrorThrowOutOfMemory()` never tries to create a new OOM error structure, and simply immediately aborts if one is unavailable. Rather than clearing the global, it keeps it around for subsequent use.
1 parent c303a65 commit b62fad6

File tree

2 files changed

+9
-9
lines changed

2 files changed

+9
-9
lines changed

docs/notes/bugfix-18925.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Prevent crashes on memory exhaustion

libfoundation/src/foundation-error.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -397,18 +397,17 @@ MCErrorCreateAndThrow (MCTypeInfoRef p_error_type, ...)
397397
MC_DLLEXPORT_DEF
398398
bool MCErrorThrowOutOfMemory(void)
399399
{
400-
if (s_out_of_memory_error == nil &&
401-
!MCErrorCreate(kMCOutOfMemoryErrorTypeInfo, nil, s_out_of_memory_error))
400+
if (s_out_of_memory_error == nil)
402401
{
403-
exit(-1);
404-
return false;
402+
/* This function may be being called from within
403+
* MCMemoryNew(). If there is no error structure already
404+
* allocated, calling MCErrorCreate() to obtain one will call
405+
* MCMemoryNew()... which will re-enter this function,
406+
* probably recursively until the stack overflows. */
407+
abort();
405408
}
406409

407-
MCErrorThrow(s_out_of_memory_error);
408-
MCValueRelease(s_out_of_memory_error);
409-
s_out_of_memory_error = nil;
410-
411-
return false;
410+
return MCErrorThrow(s_out_of_memory_error);
412411
}
413412

414413
MC_DLLEXPORT_DEF

0 commit comments

Comments
 (0)