diff --git a/src/override/malloc.cc b/src/override/malloc.cc index 218191e..f27cd75 100644 --- a/src/override/malloc.cc +++ b/src/override/malloc.cc @@ -40,10 +40,10 @@ extern "C" { bool overflow = false; size_t sz = bits::umul(size, nmemb, overflow); - if (overflow) + if (overflow || ((nmemb | size) == (size_t)-1)) { errno = ENOMEM; - return 0; + return nullptr; } // Include size 0 in the first sizeclass. sz = ((sz - 1) >> (bits::BITS - 1)) + sz; @@ -135,7 +135,12 @@ extern "C" return nullptr; } - uint8_t sc = size_to_sizeclass((std::max)(size, alignment)); + size = (std::max)(size, alignment); + if (size >= SUPERSLAB_SIZE) + { + return SNMALLOC_NAME_MANGLE(malloc)(size); + } + uint8_t sc = size_to_sizeclass(size); if (sc >= NUM_SIZECLASSES) { // large allocs are 16M aligned. diff --git a/src/test/func/malloc/malloc.cc b/src/test/func/malloc/malloc.cc new file mode 100644 index 0000000..fd8eb2d --- /dev/null +++ b/src/test/func/malloc/malloc.cc @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include +#include + +using namespace snmalloc; + +constexpr size_t min_pow_2 = bits::ctz_const(sizeof(size_t)); +constexpr size_t max_pow_2 = bits::ctz_const(SUPERSLAB_SIZE); + +size_t rand_pow_2(xoroshiro::p128r64& r, size_t min_pow = min_pow_2) +{ + const size_t max_pow = max_pow_2 - min_pow; + auto p = (r.next() % (max_pow + 1)) + min_pow; + return (size_t)1 << p; +} + +size_t rand_non_pow_2(xoroshiro::p128r64& r, size_t min = 0) +{ + const size_t max = (1 << max_pow_2) - min; + auto n = (r.next() % (max + 1)) + min; + while (__builtin_popcount(n) < 2) + n = r.next(); + + return n; +} + +void check_result(size_t size, void* p, int err, bool null) +{ + fprintf(stderr, "%p, errno: %s\n", p, strerror(errno)); // TODO + assert(errno == err); + if (null) + { + assert(p == nullptr); + } + else + { + assert(malloc_usable_size(p) >= size); + free(p); + } +} + +void test_calloc(size_t nmemb, size_t size, int err, bool null) +{ + fprintf(stderr, "calloc(%d, %d)\n", (int)nmemb, (int)size); + errno = 0; + void* p = calloc(nmemb, size); + + if ((p != nullptr) && (errno == 0)) + for (size_t i = 0; i < (size * nmemb); i++) + assert(((uint8_t*)p)[i] == 0); + + check_result(nmemb * size, p, err, null); +} + +void test_realloc(void* p, size_t size, int err, bool null) +{ + fprintf(stderr, "realloc(%p, %d)\n", p, (int)size); + errno = 0; + p = realloc(p, size); + check_result(size, p, err, null); +} + +void test_posix_memalign(size_t size, size_t align, int err, bool null) +{ + fprintf(stderr, "posix_memalign(&p, %d, %d)\n", (int)align, (int)size); + void* p = nullptr; + errno = posix_memalign(&p, align, size); + check_result(size, p, err, null); + if (!null) + assert(((uintptr_t)p % align) == 0); +} + +void test_memalign(size_t size, size_t align, int err, bool null) +{ + fprintf(stderr, "memalign(%d, %d)\n", (int)align, (int)size); + errno = 0; + void* p = memalign(align, size); + check_result(size, p, err, null); + if (!null) + assert(((uintptr_t)p % align) == 0); +} + +int main(int argc, char** argv) +{ + UNUSED(argc); + UNUSED(argv); + + constexpr int SUCCESS = 0; + + auto r = xoroshiro::p128r64((size_t)time(nullptr)); + + size_t n, s; + do + { + n = rand_pow_2(r); + s = rand_pow_2(r); + } while ((n * s) > (1 << max_pow_2)); + test_calloc(n, s, SUCCESS, false); + test_calloc(0, 0, SUCCESS, false); + test_calloc((size_t)-1, 1, ENOMEM, true); + + test_realloc(malloc(rand_pow_2(r)), 0, SUCCESS, true); + test_realloc(nullptr, rand_pow_2(r), SUCCESS, false); + test_realloc(malloc(rand_pow_2(r)), (size_t)-1, ENOMEM, true); + + test_posix_memalign(rand_pow_2(r), rand_pow_2(r), SUCCESS, false); + test_posix_memalign(0, 0, EINVAL, true); + test_posix_memalign(0, rand_pow_2(r), SUCCESS, false); + test_posix_memalign((size_t)-1, 0, EINVAL, true); + test_posix_memalign(0, rand_non_pow_2(r), EINVAL, true); + test_posix_memalign((size_t)-1, rand_pow_2(r), ENOMEM, true); + + test_memalign(rand_pow_2(r), rand_pow_2(r), SUCCESS, false); + + // snmalloc and glibc pass, not jemalloc + test_memalign((size_t)-1, rand_pow_2(r), ENOMEM, true); + + // glibc passes, not snmalloc or jemalloc + // test_memalign((size_t)-1, 0, ENOMEM, true); + + return 0; +} diff --git a/src/test/func/rounding/rounding.cc b/src/test/func/rounding/rounding.cc index e15cfd6..8c3a9e8 100644 --- a/src/test/func/rounding/rounding.cc +++ b/src/test/func/rounding/rounding.cc @@ -1,7 +1,4 @@ #include -#include -#include -#include using namespace snmalloc;