Commit Graph

54 Commits

Author SHA1 Message Date
Nathaniel Wesley Filardo
6424edaeaa Stop playing OO games with MetaEntry
David points out that the downcasts I had introduced were UB.  Instead, go back
to passing MetaEntry-s around and make MetaslabMetaEntry just a namespace of
static methods.

This partially reverts 7940fee00c
2022-03-25 14:30:13 +00:00
Matthew Parkinson
bdb3183989 Remove std::cout
Now we have an allocation free formatting routine, remove std::cout
from tracing.
2022-03-24 08:01:09 +00:00
Nathaniel Wesley Filardo
7940fee00c Refactor MetaEntry remote_and_sizeclass
Introduce a class that we can use to more completely separate the frontend
encoding details from the backend.
2022-03-21 23:21:24 +00:00
Matthew Parkinson
5287000453 Buddy (#468)
# Small changes before rewrite

* Additional bit in remote allocator to prevent type confusion with the backend.
* Move Chunk allocator to backend.
* Improvements to RedBlack tree
* Expose message from Pal

# Complete backend rewrite

This provides two key changes:

* We use buddy allocators to allow memory to reconsolidated
* The backend is factored into a series of small operations that
    allocate and deallocate memory.

The backend now uses "Ranges", there are two ranges that don't require a
parent range:
* EmptyRange - Never returns any memory
* PalRange - Returns memory from the platform.

All other ranges require a parent range to supply memory to them.  Some
ranges support both allocation and deallocation, and some just
deallocation.  For instance,  CommitRange supports both, and maps
requests to the parent range, but will Commit and Decommit the memory.

As the ranges perform only a single task, they are generally small and
easy to follow.  The two exceptions to this are the two BuddyRanges
(Large and Small).  Large is for CHUNK_SIZE and above blocks, while
Small is for below CHUNK_SIZE blocks.  Both are implemented with a buddy
allocator, but the SmallBuddyRange uses in place meta-data, while the
LargeBuddyRange uses the pagemap for its meta-data.  This means the
LargeBuddyRange can keep the majority of memory it is managing
decommitted.

The Backend glues together the various ranges to support the appropriate
way to manage memory on the platform.
2022-03-11 18:16:06 +00:00
Robert Norton
86aa28644c Errno fix (#463)
Correctly set errno on failure and improve the related test.

Previously the malloc test would emit an error message but not
abort if the errno was not as expected on failure. This
was because the return in the null == true case prevented the
check for failed == true at the end of check_result from
being reached. To resolve this just abort immediately as in the 
null case.

Also add tests of allocations that are expected to fail for
calloc and malloc.

To make the tests pass we need to set errno in several places,
making sure to keep this off the fast path.

We must also take care not to attempt to zero nullptr in case
of calloc failure.

See microsoft/snmalloc#461 and microsoft/snmalloc#463.
2022-02-24 10:09:29 +00:00
Matthew Parkinson
eb00f3184f Remove local state from Pagemap representation. 2022-02-11 13:21:46 +00:00
Matthew Parkinson
ef64f6c31b Improve check_bounds init check. 2022-01-10 16:29:06 +00:00
David Chisnall
4ea978b946 Remove fake_large_remote
Since #441 was merged, pagemap entries are no longer ever set to
fake_large_remote.
2022-01-07 16:29:11 +00:00
Matthew Parkinson
61314f2260 Post large deallocations to original thread (#441)
* Post large deallocations to original thread

This change sets all large allocations to be owned by the originating
thread. This means they will be messaged back to the original thread
before they can be reused.

The following reason for making this change:
* This will improve producer/consumer apps involving large allocations.
* It enables the implementation of a more complex chunk allocator that
reassembles chunks.
* It addresses an issue with compartmentalisation where the handling of
large allocations can result in meta-data ownership changing.
2021-12-17 14:08:08 +00:00
Nathaniel Wesley Filardo
3fb7c98364 That's snmalloc_check_client to you.
c299826f58 landed as part of #428 while #416 was
still outstanding and not all conflicts are textual.  Sorry!
2021-12-17 13:45:42 +00:00
Nathaniel Wesley Filardo
b777243981 Additional CHERI client checks 2021-12-16 19:25:09 +00:00
Nathaniel Wesley Filardo
22a05b4a3c CHERI: dealloc() use cap base, not address 2021-12-16 19:25:09 +00:00
Matthew Parkinson
c299826f58 Improve codegen for checks.
Use fail fast in release to avoid stack frame for error reporting.

Scope check_client macro.
2021-11-25 08:22:28 +00:00
Matthew Parkinson
a8ef963ed7 Small comment 2021-11-25 08:22:28 +00:00
Schrodinger ZHU Yifan
faa80037bb put likely/unlikely in scope (#420)
* put likely/unlikely in scope

Signed-off-by: SchrodingerZhu <i@zhuyi.fan>

* make clang-format happy

Signed-off-by: SchrodingerZhu <i@zhuyi.fan>
2021-11-17 16:05:52 +00:00
Matthew Parkinson
3d403aef7f Refactor use of sizeclasses (#415)
The primary aim for this refactor is to use a representation for
sizeclasses that uniformly covers both large and small.  This allows
certain operations such as alloc_size and external_pointer to be
uniformly implemented.

The additional types make clear which kind of sizeclass is in use.

This also tidies up the code for sizeclass based divisible by and
modulus.

It fixes a bug in rust_realloc that didn't correctly determine a realloc
was required for large classes.
2021-11-10 16:35:44 +00:00
Matthew Parkinson
72ccb23d02 Add local caching to chunk allocator 2021-10-28 14:28:36 +01:00
Nathaniel Wesley Filardo
3cdb7be478 MetaEntry: split get_metaslab by intent 2021-10-20 12:02:08 +01:00
Nathaniel Wesley Filardo
599ae0e632 Metaslab: add MetaCommon field
This preserves the chunk pointer through the use of a chunk as a slab.  It does
grow the structure by one pointer, but on non-CHERI it is still padded to 64
bytes, even with CHECK_CLIENT guards in place:

 0: MetaCommon chunk pointer
 8: next pointer
16: builder head[0]
24: builder head[1]
32: builder tail[0]
40: builder tail[1]
48: builder length[0] (uint16_t)
50: builder length[1] (uint16_t)
52: padding (4 bytes)
56: needed (uint16_t)
58: sleeping (bool)

(Sadly, on CHERI, even without CHECK_CLIENT guards and with no padding, there
are now four pointers in the structure -- chunk, next, head, tail -- plus five
extra bytes.  We will likely wish to explore encoding the head and tail offsets
relative to the chunk pointer.)

This lets us remove the "subversive amplification" in dealloc() in favor of just
preserving the chunk pointer.  Speaking of, be sure to assign that in all the
right places, and ASSERT that we've got it right.
2021-10-20 12:02:08 +01:00
Nathaniel Wesley Filardo
6c115eec18 NFC: doc tweaks 2021-10-20 12:02:08 +01:00
Nathaniel Wesley Filardo
f0b7dc4b04 NFC: Extract MetaCommon from ChunkRecord 2021-10-20 12:02:08 +01:00
Nathaniel Wesley Filardo
5bb556cb68 Convert alloc paths to capptr::Alloc<void>
The use of void* had let an overzealous unsafe_ptr() leak a pointer with address
space control to the client (in LocalAllocator::alloc_not_small, specifically).
Correct this to call capptr_chunk_is_alloc() (to capture our intent) and
capptr_to_user_address_control() (to do the bounding) and defer the conversion
to void* until the very periphery of the allocator, using capptr_reveal()
(again, to capture intent).
2021-10-20 12:02:08 +01:00
Nathaniel Wesley Filardo
554db3997d localalloc::dealloc tweak size math for large objects
Avoid computing bits::next_pow2_bits(1 << n).  Even if the compiler can see
through enough of the algebra, it's surely more direct to just use n.

While here, slightly expand documentation about what's going on with the
"sizeclass" encoded into MetaEntry-s.
2021-10-20 12:02:08 +01:00
Nathaniel Wesley Filardo
c54d2b527d NFC: CapPtr in external_pointer; drop capptr_rebound
capptr_rebound was only ever going to be used for external_pointer, which now
operates entirely using pointer_offset.  So instead, just make external_pointer
use capptr::AllocWild<void>, capptr_from_client, and a new capptr_reveal_wild.
2021-10-20 12:02:08 +01:00
Nathaniel Wesley Filardo
96155db640 Collect freelist things in a namespace
Motivated by renaming `FreeObject::{Head,Queue,AtomicQueue}Ptr` to
`freelist::...Ptr`, in fact go further, moving `FreeObject` itself to
`freelist::Object` and `FreeListBuilder` to `freelist::Builder` and
`FreeListIter` to `freelist::Iter`
2021-10-13 16:30:41 +01:00
Nathaniel Wesley Filardo
bc365e0abb Default template args for FreeObject & friends
Now that explicit annotations have gotten us through the refactoring, it's time
for the scaffolding to disappear.  src/mem/freelist.h is left generic for any
future machinations, but `FreeObject::T<>`, the several `FreeObject::...Ptr<>`s,
`FreeListIter<>`, and `FreeListBuilder<>` are given default parameters and all
uses are shortened to use defaults where possible.
2021-10-13 16:30:41 +01:00
Nathaniel Wesley Filardo
d4c120dfe5 Free queues hold Wild pointers 2021-10-13 16:30:41 +01:00
Nathaniel Wesley Filardo
7750676598 NFC: FreeListIter domestication plumbing
Just an intermediate syntactic step to chase dependencies.  All these introduced
"domestication" callbacks are just the identity function, but they will let us
thread the LocalAlloc's handle to the Backend state down to where it's needed.
2021-10-13 16:30:41 +01:00
Nathaniel Wesley Filardo
a34b7a5973 Make capptr_from_client return a Wild CapPtr
Chase consequences in dealloc().
2021-10-13 16:30:41 +01:00
Nathaniel Wesley Filardo
1a608e6066 NFC: Introduce pointer domestication backend support
`capptr_domesticate<Backend>(Backend::LocalState*, CapPtr<T, B>)` is the
intended affordance for conversion to covert from a `CapPtr<T, B>` with
`B::wildness` `Wild` to a `CapPtr<>` with `B::with_wildness<Tame>` and thence
plumbed into the rest of the machinery.

David added the SFINAE wrapper so that `Backend`-s now don't need to implement a
domestication callback; instead, if the `Backend` does not provide a
`capptr_domesticate` function, a default, which just does an explicit type cast,
will be used instead.

This is not yet hooked into the rest of the tree.

Co-authored-by: David Chisnall <David.Chisnall@microsoft.com>
2021-10-13 16:30:41 +01:00
Nathaniel Wesley Filardo
7e53a2e82a CapPtr: shift free lists to Alloc bounds
This is incomplete, yet still more reflective of what's going on: we take the
exported pointers back from userspace and thread them directly into the free
lists.

So: move capptr_to_user_address_control to list construction time rather than
list consumption time.
2021-10-13 16:30:41 +01:00
Nathaniel Wesley Filardo
e25db7b832 Move to FreeObject::T<capptr::bound<>>
FreeObject itself is now just a namespace (but `friend`-ly); the actual free
list nodes are FreeObject::T-s that are templatized on the (perceived)
`capptr::bound<>` of the pointer they contain.  (These may differ across an
instantiated snmalloc; for example, in the sandboxing design, the in-sandbox
allocators may perceive all remotes to be full of `AllocUser` while the
privileged allocator of sandbox memory should perceive its remote queue as
holding `AllocUserWild` pointers in need of domestication.)

The interfaces to `FreeObject::T`-s now let us distinguish between the base and
inductive cases of the queues:

* in the inductive case, the pointer we hold to a `FreeObject::T` and its
  next_object have the same bounds

* in the base case, the pointer we hold has different bounds (typically,
  domesticated by contrast to the wild pointers in the queues).

To keep the clutter down a bit, we occasionally use raw pointers when we can be
reasonably certain that domestication is assured.  Moreover, we define some type
aliases, `FreeObject::{HeadPtr, QueuePtr, AtomicQueuePtr}`, that are slightly
more convenient labels than, e.g., `CapPtr<FreeObject::T<BQueue>, BView>`.
Because we are using template parameters for the `capptr::bound<>`s themselves,
we cannot use the aliases for `CapPtr<>s` provided within `capptr::`.

The two primary interfaces around free objects (`FreeListIter` AND
`FreeListBuilder`) are adjusted appropriately and their `BView` and `BQueue`
template paramters are plumbed explicitly around the tree.  This makes for quite
a bit of noise at the moment, but means that we'll be able to evolve parts of
the tree separately and can consider putting defaults in once that's done.
2021-10-13 16:30:41 +01:00
Nathaniel Wesley Filardo
9065893181 Overhaul CapPtr
* Switch to a multidimensional taxonomy.

  Rather than encoding the abstract bound states in a single enum, move to a
  more algebraic treatment.  The dimensions themselves are within the
  snmalloc::capptr_bounds namespace so that their fairly generic names do not
  conflict with consumer code.  Aliases for many points in the space are
  established outside that namespace for ease of use elsewhere.

* Introduce several new namespaces:

    * snmalloc::capptr::dimension holds each of the dimension enums

    * snmalloc::capptr holds the bound<> type itself and a ConceptBound

    * snmalloc::capptr::bounds gives convenient specializations of bound<>

    * snmalloc::capptr also has aliases for CapPtr<> itself

  All told, rather than `CapPtr<T, CBChunk>`, we now expect client code to read
  `capptr::Chunk<T>` in almost all cases (and this is just an alias for the
  appropriate `CapPtr<T, bounds<...>>` type).  When the bound<>s themselves are
  necessary, as when calling capptr_bound, we expect that they will almost
  always be pronounced using an alias (e.g., `capptr::bounds::Alloc`).

* Chase consequences.

* Prune old taxa and aliases that are no longer in use in snmalloc2.
2021-10-13 16:30:41 +01:00
David Chisnall
51e75bca89 Add memcpy with bounds checks.
The memcpy implementation is not completely stupid but is almost
certainly not as good as a carefully tuned and optimised one.

Building snmalloc with FreeBSD's libc memcpy + jemalloc and with this,
each 10 times, does not show a statistically significant performance
difference at 95% confidence.  The snmalloc version has very slightly
lower median and worst-case times.  This is in no way a sensible
benchmark, but it serves as a smoke test for significant performance
regressions.

The CI self-host job now uses the checked memcpy.

This also fixes an off-by-one error in the external bounds.  This is
triggered by ninja, so we will see breakage in CI if it is reintroduced.

In debug builds, we provide a verbose error containing the address of
the allocation, the base and bounds of the allocation, and a backtrace.

The backtrace was broken by the CI cleanup moving the BACKTRACE_HEADER
macro into the SNMALLOC_ namespace.  This is also fixed.

The test involves hijacking `abort`, which doesn't work everywhere.  It
also requires `backtrace` to work in configurations where stack traces
are enabled.  This is disabled in QEMU because `backtrace` appears to
crash reliably in QEMU user mode.

For now, in the -checks build configurations, we are hitting a slow path
in the pagemap on accesses so that the pages that are `PROT_NONE` don't
cause crashes.  These need to be made read-only, but this requires a PAL
change.
2021-09-16 13:53:13 +01:00
Nathaniel Wesley Filardo
3af9d35099 Plumb LocalState ptrs through to Pagemap accessors
David points out that we might not have a static way to get at the pagemap, so
it is potentially useful to pass pointers to state objects down from the
Allocators.
2021-08-26 16:53:52 +01:00
Nathaniel Wesley Filardo
2be44d2e6f Use backend global concept on template args
Wire the concept into the rest of the tree, being careful to avoid demanding the
result of fixed-pointing computation while tying the knot.
2021-08-26 16:53:52 +01:00
Nathaniel Wesley Filardo
f913f8b820 Rename [gs]et_meta_data to [gs]et_metaentry.
Co-authored-by: David Chisnall <David.Chisnall@microsoft.com>
2021-08-26 16:53:52 +01:00
Nathaniel Wesley Filardo
70c3e00df7 AddressSpace: use Backend to access Pagemap
And do so by type, rather than by value.  While here, introduce a C++20 concept
for this Backend-offered proxy and adjust the template parameters appropriately.

This will be useful for the process sandbox code, which needs to mediate stores
to the pagemap, but can provide a read-only view.
2021-08-26 16:53:52 +01:00
Matthew Parkinson
7eb8769950 Fix codegen for dealloc
The PR #359 regressed codegen for deallocation. This fixes it.
2021-08-26 14:47:56 +01:00
Matthew Parkinson
27c4a6a55e Make pagemap check for init on some gets.
When we are accessing potentially out of range, then we might be
accessing before the pagemap has been initialised.  Move the check
into the pagemap for better codegen.
2021-08-26 14:47:56 +01:00
Matthew Parkinson
44416ed70e Factor sizeclass meta-data for cache locality
This commit splits the sizeclass meta-data to generate better cache
locality for various lookups for checking for size and start of
sizeclasses.

Also, contains some tidying including removing sizeclasses covering
large range. This is left over from an alternative design for large
classes that is no longer in use.
2021-08-26 14:47:56 +01:00
Matthew Parkinson
0f70494d55 Enable passthrough to an underlying allocator
This passes though to an underlying allocator rather than using
snmalloc.  This is required for using ASAN in Verona.  Verona takes a
close coupling with snmalloc, but to use with ASAN would require a
more work, so we pass to the system allocator in this case.
2021-08-26 14:34:36 +01:00
Istvan Haller
95d33d777b Merge pull request #377 from ihaller/ihaller/generic-pool
Changes to integrate snmalloc2 into Verona
2021-08-25 15:17:16 +01:00
Istvan Haller
c01a1215c6 Cleanup and made new variant work with Verona 2021-08-23 21:07:51 +01:00
Istvan Haller
769c61e716 Moved SharedStateHandle to Pool class instead of methods since all of them use it 2021-08-23 20:08:27 +01:00
Istvan Haller
c89a085c90 Removed code duplication by making generoc Pool also be static 2021-08-23 19:54:26 +01:00
Istvan Haller
35c9422913 Comment fixes 2021-08-23 19:19:58 +01:00
Istvan Haller
4d2bf93b7a Deleted the ability to implicitly copy LocalAllocator 2021-08-23 16:37:21 +01:00
David Chisnall
2d4a4caab7 Fix the type checker. 2021-08-23 11:15:11 +01:00
Istvan Haller
99f57646da Re-enabled generic Pool which uses ChunkAllocator. Allocator pool renamed to AllocPool. 2021-08-20 15:28:38 +01:00