Make mmc cache replacement signal-safe - #51
Draft
cxzhong wants to merge 1 commit into
Draft
Conversation
cxzhong
force-pushed
the
agent/make-mmc-cache-replacement-signal-safe
branch
2 times, most recently
from
August 4, 2026 10:40
9ee951e to
eab7db6
Compare
Keep MMC cache slot state valid at each interruptible store so a stale size cannot be paired with a NULL or smaller data pointer after a signal-driven non-local exit. Bypass MMC caching in OpenMP builds to avoid leaving the OpenMP critical lock held if a signal handler siglongjmp skips the runtime unlock path. Add MMC coverage for cache reuse, stale empty slot repair, cleanup of unpublished slots, and the OpenMP cache-bypass configuration.
cxzhong
force-pushed
the
agent/make-mmc-cache-replacement-signal-safe
branch
from
August 4, 2026 11:36
eab7db6 to
ad807de
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Make MMC cache state transitions robust when an embedding application leaves an M4RI call through a signal-driven non-local exit.
The cache now preserves a recoverable ownership state at every interruptible store, avoids exposing released storage through stale slot metadata, and makes a retried cache insertion idempotent. MMC is also disabled in OpenMP builds, where a non-local exit from an OpenMP critical region could otherwise leave the runtime lock held.
Problem
Each MMC slot stores a pointer and its allocation size. The previous replacement path released the pointer already stored in a slot before publishing the replacement pointer and size:
If control left the function between these operations, the global cache could still describe storage that had already been released. A later allocation could return that stale pointer, causing allocator corruption, a double free, or a segmentation fault.
There were related partial-update states in cache allocation and cleanup:
Cache state model
The updated code treats the pointer field as the authoritative ownership indicator:
data == NULL, size == 0is an empty slotdata != NULL, size == 0is an interrupted but recoverable publicationdata != NULL, size != 0is a fully published cached allocationStores are performed through a volatile cache view so optimized builds preserve the required publication order. A new pointer is published only after the size is cleared, and the size is written last. Removing a pointer clears the size before clearing the pointer.
This means an interruption can leave either a valid published entry or a recoverable entry, but not a nonzero size paired with a missing or unrelated pointer.
Allocation changes
m4ri_mmc_malloc()now:Release changes
m4ri_mmc_free()now scans the complete cache before publishing a pointer:size = 0,data = pointer,size = allocation_sizeorderThe complete scan is important because an empty slot can appear before a later slot that already owns the same pointer. Returning at the first empty slot would reintroduce duplicate ownership.
NULL pointers, zero-sized allocations, and allocations at or above the cache threshold continue to use the normal allocator path.
Cleanup changes
m4ri_mmc_cleanup()now usesdata != NULLto decide whether a slot owns storage. It clears the slot before releasing the pointer, which prevents a non-local exit from leaving a globally reachable dangling pointer that could later be returned or freed again.Cleanup also resets stale size metadata for empty slots and reclaims interrupted publications where the pointer is present but the size has not yet been published.
OpenMP behavior
MMC is disabled when OpenMP support is enabled. The cache is process-global and its critical regions cannot be made robust when a signal handler performs a non-local exit past the OpenMP runtime's unlock path. Bypassing MMC in this configuration avoids both stale cache state and a permanently held OpenMP lock.
The implementation also keeps a local compile-time guard so an inconsistent configuration cannot accidentally activate the cache in an OpenMP build.
Scope
This change makes the MMC cache's own state transitions recoverable and prevents the stale-pointer and duplicate-ownership failures described above. It does not make the system allocator generally async-signal-safe, nor can a pointer-returning API atomically transfer ownership to a caller that may perform a non-local exit before accepting the return value.
Applications that require recovery from arbitrary signal-handler non-local exits across allocation or release calls still need to block the relevant signals across that API boundary or provide an explicit ownership acknowledgement protocol.