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
@@ -115,4 +115,26 @@ namespace snmalloc
|
||||
&unused_remote != fake_large_remote,
|
||||
"Compilation should ensure these are different");
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
} // namespace snmalloc
|
||||
|
||||
@@ -244,7 +244,14 @@ namespace snmalloc
|
||||
}
|
||||
|
||||
// This means external pointer on Windows will be slow.
|
||||
if constexpr (potentially_out_of_range && !pal_supports<LazyCommit, PAL>)
|
||||
// TODO: With SNMALLOC_CHECK_CLIENT we should map that region read-only,
|
||||
// not no-access, but this requires a PAL change.
|
||||
if constexpr (
|
||||
potentially_out_of_range
|
||||
#ifndef SNMALLOC_CHECK_CLIENT
|
||||
&& !pal_supports<LazyCommit, PAL>
|
||||
#endif
|
||||
)
|
||||
{
|
||||
register_range(p, 1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user