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.
This commit is contained in:
committed by
David Chisnall
parent
d524ef5cac
commit
51e75bca89
@@ -287,27 +287,6 @@ namespace snmalloc
|
||||
return local_cache.remote_allocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* SFINAE helper. Matched only if `T` implements `is_initialised`. Calls
|
||||
* it if it exists.
|
||||
*/
|
||||
template<typename T>
|
||||
SNMALLOC_FAST_PATH auto call_is_initialised(T*, int)
|
||||
-> decltype(T::is_initialised())
|
||||
{
|
||||
return T::is_initialised();
|
||||
}
|
||||
|
||||
/**
|
||||
* SFINAE helper. Matched only if `T` does not implement `is_initialised`.
|
||||
* Unconditionally returns true if invoked.
|
||||
*/
|
||||
template<typename T>
|
||||
SNMALLOC_FAST_PATH auto call_is_initialised(T*, long)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call `SharedStateHandle::is_initialised()` if it is implemented,
|
||||
* unconditionally returns true otherwise.
|
||||
@@ -639,9 +618,9 @@ namespace snmalloc
|
||||
if constexpr (location == Start)
|
||||
return start;
|
||||
else if constexpr (location == End)
|
||||
return pointer_offset(start, rsize);
|
||||
else
|
||||
return pointer_offset(start, rsize - 1);
|
||||
else
|
||||
return pointer_offset(start, rsize);
|
||||
}
|
||||
#else
|
||||
UNUSED(p_raw);
|
||||
@@ -649,7 +628,7 @@ namespace snmalloc
|
||||
|
||||
if constexpr ((location == End) || (location == OnePastEnd))
|
||||
// We don't know the End, so return MAX_PTR
|
||||
return pointer_offset<void, void>(nullptr, UINTPTR_MAX);
|
||||
return reinterpret_cast<void*>(UINTPTR_MAX);
|
||||
else
|
||||
// We don't know the Start, so return MIN_PTR
|
||||
return nullptr;
|
||||
|
||||
Reference in New Issue
Block a user