From 56fe75eef49491cd5689496560381412ed5280a1 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Wed, 6 May 2026 06:46:03 -0700 Subject: [PATCH] fix: prevent corruption of the small allocator state (#13548) This PR fixes possible corruption when recovering from memory exhaustion. This code threw an `std::bad_alloc` in the case of memory exhaustion, but left the small allocator in an inconsistent state when doing so. This would mean any code catching and recovering from the allocation failure would likely find itself with a corrupt small allocator. While we could try and make this code exception safe in future, simply making it panic is better than the status quo, and is consistent with how we handle most other allocation failures. changelog-please-rerun-the-changelog-ci --- src/runtime/alloc.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/runtime/alloc.cpp b/src/runtime/alloc.cpp index d35dafefdc..f05139f765 100644 --- a/src/runtime/alloc.cpp +++ b/src/runtime/alloc.cpp @@ -270,8 +270,8 @@ void heap::export_objs() { } void heap::alloc_segment() { - LEAN_RUNTIME_STAT_CODE(g_num_segments++); segment * s = new segment(); + LEAN_RUNTIME_STAT_CODE(g_num_segments++); s->m_next = m_curr_segment; m_curr_segment = s; } @@ -283,8 +283,13 @@ static page * alloc_page(heap * h, unsigned obj_size) { page * p = new (s->m_next_page_mem) page(); s->m_next_page_mem += LEAN_PAGE_SIZE; if (s->is_full()) { - /* s is full, we need to allocate a new one. */ - h->alloc_segment(); + try { + /* s is full, we need to allocate a new one. */ + h->alloc_segment(); + } catch (std::bad_alloc const&) { + /* `s` is now in an inconsistent state so it would be unsafe to propagate the exception */ + lean_internal_panic_out_of_memory(); + } } unsigned slot_idx = lean_get_slot_idx(obj_size); p->m_header.m_heap = h;