Read the batched remote free ring's length word without domesticating it - #877
Merged
Matthew Parkinson (mjp41) merged 1 commit intoSep 8, 2026
Conversation
Contributor
Author
|
@microsoft-github-policy-service agree |
Matthew Parkinson (mjp41)
approved these changes
Sep 7, 2026
Matthew Parkinson (mjp41)
left a comment
Member
There was a problem hiding this comment.
LGTM, Nathaniel Wesley Filardo (@nwf) are you happy with this.
Nathaniel Wesley Filardo (nwf)
approved these changes
Sep 8, 2026
Nathaniel Wesley Filardo (nwf)
left a comment
Contributor
There was a problem hiding this comment.
LGTM. Thanks again!
Sebastian Blessing (sblessing)
force-pushed
the
fix-remote-ring-domestication
branch
from
September 8, 2026 02:20
4d53e1a to
16bf252
Compare
BatchedRemoteMessage::mk_from_freelist_builder() closes the free ring by storing a bit-packed (displacement, length) word, not a pointer, in the ring's next field. open_free_ring() and ring_size() read it back through freelist::Object::T::read_next(), which passes the decoded value through the config's domesticator. A domesticator that rejects addresses outside the heap (FixedRangeConfig::capptr_domesticate() returns nullptr for them) turns the word into 0, so every incoming ring decodes as length 0 and every batched remote deallocation is leaked. With FixedRangeConfig the fixed region is exhausted by remote frees alone even though the program frees everything it allocates. Add freelist::Object::T::read_next_raw(), which undoes the free-list encoding but does not domesticate, and define read_next() in terms of it so the difference between the two is the single domestication call. Use read_next_raw() for the ring word; the pointer derived from its displacement is still domesticated separately, as before. Add the reproducer as func/fixed_region_remote_dealloc: one allocator allocates from a FixedRangeConfig region, another frees remotely and flushes, for more rounds than the region could survive if the frees were lost. It aborts on the unpatched tree and completes with this change. Fixes microsoft#876.
Sebastian Blessing (sblessing)
force-pushed
the
fix-remote-ring-domestication
branch
from
September 8, 2026 02:21
16bf252 to
d60aacf
Compare
Matthew Parkinson (mjp41)
enabled auto-merge (squash)
September 8, 2026 04:41
Sebastian Blessing (sblessing)
deleted the
fix-remote-ring-domestication
branch
September 8, 2026 05:46
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.
Fixes #876.
Problem
BatchedRemoteMessage::mk_from_freelist_builder()closes the free ring by storing a bit-packed(displacement << MAX_CAPACITY_BITS) + lengthword in the ring'snextfield. On the receiving side,open_free_ring()andring_size()read that word back throughfreelist::Object::T::read_next(), which passes the decoded value through the config's domesticator as if it were a pointer.A domesticator that does its job and rejects anything outside the heap (
FixedRangeConfig::capptr_domesticate()returnsnullptrfor out-of-range addresses) turns the word into 0. Every incoming ring then decodes as length 0, the slab'sneededcount is never decremented, and every batched remote deallocation is leaked. WithFixedRangeConfiga fixed region is exhausted by remote frees alone even though the program frees everything it allocates. The defaultStandardConfighas an identity domesticator, which is why the mainstream configuration was unaffected.Fix
freelist::Object::T::read_next_raw(), which undoes the free-list encoding of thenextfield but does not domesticate the result. Per Nathaniel Wesley Filardo (@nwf)'s review comment on the issue,read_next()is now defined asdomesticate(read_next_raw(...)), so the difference between the two is the single domestication call.open_free_ring()andring_size()read the ring word withread_next_raw(). The pointer derived from the displacement is still domesticated separately, as before.Test
src/test/func/fixed_region_remote_deallocadds the reproducer from the issue to the test harness: allocator A allocates 64-byte objects from a 32 MiBFixedRangeConfigregion, allocator B frees them and flushes, for twice as many rounds as would be needed to exhaust the region if the remote frees were lost. On the unpatched tree it aborts in round 8144 (the whole region leaked); with the fix it completes.Existing
fixed_region,fixed_region_allocanddomesticationtests still pass in both thefastandcheckflavours.domesticate_countin thedomesticationtest drops from 5 to 4, since the ring word is no longer domesticated; that test does not assert on the count.