- CI merge issues:
- The malloc shim libraries are renamed.
- CMake gets very unhappy if you don't enable the C language and
tries to link with the C compiler instead of the C++ compiler if
you do enable it.
- The Ubuntu packages for QEMU install a `binfmt_misc` activator for
PowerPC64 little-endian, but set the page size to 4 KiB. We then
tried to run the tests (which expect 64 KiB pages) and became very
confused when `mmap` returned 4 KiB-aligned memory.
- Test failures:
- Fix all of the issues UBsan found.
- Underflow in `pointer_offset` when used to add negative offsets.
- `CoreAlloc`'s `LocalState` accessed on a null `CoreAlloc` pointer.
- Out of bounds access in the sizeclass list on attempts to access
more memory than fits in the VA space.
-
- There was an integer overflow in `AddressSpace` that could cause it
to try to allocate a zero-sized object, get a null pointer, and
then try to do something with 0 - {size of the real allocation}.
- The malloc tests weren't setting `errno` to 0 before doing
calling `malloc`, which should set `errno` on failure, and then
checking that `errno` was 0.
- Don't call `PAL::error` on PAL allocation failure, return `nullptr`.
The PALs were inconsistent about that and the new code expects to be
able to report address-space exhaustion.
- The malloc checks can behave differently with 0-sized allocations
on different platforms but were very fragile about their
expectations.
- The malloc test didn't report failure for all of the ways that it
could fail and so was spuriously passing on some platforms.
- The perf test for external pointer is currently very slow on
Windows. The number of loops have been reduced and a timeout added
for the Windows CI runs.
- The logic to capture `errno` across calls was using
`decltype(errno)`, which on some platforms where `errno` is a macro
evaluated to `int&` and so they captured a reference rather than
the value and failed to reset `errno`.
- The Apple PAL can set `errno` on `notify_using` if it's called with
memory that was not previously passed to `notify_not_using` but was
not adequately protected against this and so would sometimes cause
`malloc` to set `errno` to `EINVAL`.
109 lines
2.6 KiB
C++
109 lines
2.6 KiB
C++
#include <snmalloc.h>
|
|
#include <test/measuretime.h>
|
|
#include <test/setup.h>
|
|
#include <test/xoroshiro.h>
|
|
#include <unordered_set>
|
|
|
|
using namespace snmalloc;
|
|
|
|
namespace test
|
|
{
|
|
static constexpr size_t count_log = 20;
|
|
static constexpr size_t count = 1 << count_log;
|
|
// Pre allocate all the objects
|
|
size_t* objects[count];
|
|
|
|
NOINLINE void setup(xoroshiro::p128r64& r, Alloc& alloc)
|
|
{
|
|
for (size_t i = 0; i < count; i++)
|
|
{
|
|
size_t rand = (size_t)r.next();
|
|
size_t offset = bits::clz(rand);
|
|
if constexpr (bits::is64())
|
|
{
|
|
if (offset > 30)
|
|
offset = 30;
|
|
}
|
|
else if (offset > 20)
|
|
offset = 20;
|
|
|
|
size_t size = (rand & 15) << offset;
|
|
if (size < 16)
|
|
size = 16;
|
|
// store object
|
|
objects[i] = (size_t*)alloc.alloc(size);
|
|
if (objects[i] == nullptr)
|
|
abort();
|
|
// Store allocators size for this object
|
|
*objects[i] = alloc.alloc_size(objects[i]);
|
|
}
|
|
}
|
|
|
|
NOINLINE void teardown(Alloc& alloc)
|
|
{
|
|
// Deallocate everything
|
|
for (size_t i = 0; i < count; i++)
|
|
{
|
|
alloc.dealloc(objects[i]);
|
|
}
|
|
|
|
snmalloc::debug_check_empty<Globals>();
|
|
}
|
|
|
|
void test_external_pointer(xoroshiro::p128r64& r)
|
|
{
|
|
auto& alloc = ThreadAlloc::get();
|
|
// This is very slow on Windows at the moment. Until this is fixed, help
|
|
// CI terminate.
|
|
#if defined(NDEBUG) && !defined(_MSC_VER)
|
|
static constexpr size_t iterations = 10000000;
|
|
#else
|
|
# ifdef _MSC_VER
|
|
// Windows Debug build is very slow on this test.
|
|
// Reduce complexity to balance CI times.
|
|
static constexpr size_t iterations = 50000;
|
|
# else
|
|
static constexpr size_t iterations = 100000;
|
|
# endif
|
|
#endif
|
|
setup(r, alloc);
|
|
|
|
{
|
|
MeasureTime m;
|
|
m << "External pointer queries ";
|
|
for (size_t i = 0; i < iterations; i++)
|
|
{
|
|
size_t rand = (size_t)r.next();
|
|
size_t oid = rand & (((size_t)1 << count_log) - 1);
|
|
size_t* external_ptr = objects[oid];
|
|
size_t size = *external_ptr;
|
|
size_t offset = (size >> 4) * (rand & 15);
|
|
void* interior_ptr = pointer_offset(external_ptr, offset);
|
|
void* calced_external = alloc.external_pointer(interior_ptr);
|
|
if (calced_external != external_ptr)
|
|
abort();
|
|
}
|
|
}
|
|
|
|
teardown(alloc);
|
|
}
|
|
}
|
|
|
|
int main(int, char**)
|
|
{
|
|
#ifndef SNMALLOC_PASS_THROUGH // Depends on snmalloc specific features
|
|
setup();
|
|
|
|
xoroshiro::p128r64 r;
|
|
# ifdef NDEBUG
|
|
size_t nn = 30;
|
|
# else
|
|
size_t nn = 3;
|
|
# endif
|
|
|
|
for (size_t n = 0; n < nn; n++)
|
|
test::test_external_pointer(r);
|
|
return 0;
|
|
#endif
|
|
}
|