Merge pull request #84 from microsoft/bug-fix

Bug fix
This commit is contained in:
David Chisnall
2019-08-13 16:57:21 +01:00
committed by GitHub
14 changed files with 128 additions and 33 deletions

View File

@@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.8)
project(snmalloc C CXX) project(snmalloc C CXX)
option(USE_SNMALLOC_STATS "Track allocation stats" OFF) option(USE_SNMALLOC_STATS "Track allocation stats" OFF)
option(SNMALLOC_CI_BUILD "Disable features not sensible for CI" OFF)
option(USE_MEASURE "Measure performance with histograms" OFF) option(USE_MEASURE "Measure performance with histograms" OFF)
option(EXPOSE_EXTERNAL_PAGEMAP "Expose the global pagemap" OFF) option(EXPOSE_EXTERNAL_PAGEMAP "Expose the global pagemap" OFF)
option(EXPOSE_EXTERNAL_RESERVE "Expose an interface to reserve memory using the default memory provider" OFF) option(EXPOSE_EXTERNAL_RESERVE "Expose an interface to reserve memory using the default memory provider" OFF)
@@ -95,6 +96,10 @@ if(USE_MEASURE)
target_compile_definitions(snmalloc_lib INTERFACE -DUSE_MEASURE) target_compile_definitions(snmalloc_lib INTERFACE -DUSE_MEASURE)
endif() endif()
if(SNMALLOC_CI_BUILD)
target_compile_definitions(snmalloc_lib INTERFACE -DSNMALLOC_CI_BUILD)
endif()
if(CACHE_FRIENDLY_OFFSET) if(CACHE_FRIENDLY_OFFSET)
target_compile_definitions(snmalloc_lib INTERFACE -DCACHE_FRIENDLY_OFFSET=${CACHE_FRIENDLY_OFFSET}) target_compile_definitions(snmalloc_lib INTERFACE -DCACHE_FRIENDLY_OFFSET=${CACHE_FRIENDLY_OFFSET})
endif() endif()
@@ -158,7 +163,7 @@ if(NOT DEFINED SNMALLOC_ONLY_HEADER_LIBRARY)
aux_source_directory(${TESTDIR}/${TEST_CATEGORY}/${TEST} SRC) aux_source_directory(${TESTDIR}/${TEST_CATEGORY}/${TEST} SRC)
set(TESTNAME "${TEST_CATEGORY}-${TEST}-${SUPER_SLAB_SIZE}") set(TESTNAME "${TEST_CATEGORY}-${TEST}-${SUPER_SLAB_SIZE}")
add_executable(${TESTNAME} ${SRC} src/override/new.cc) add_executable(${TESTNAME} ${SRC})
if (${SUPER_SLAB_SIZE} EQUAL 1) if (${SUPER_SLAB_SIZE} EQUAL 1)
target_compile_definitions(${TESTNAME} PRIVATE IS_ADDRESS_SPACE_CONSTRAINED) target_compile_definitions(${TESTNAME} PRIVATE IS_ADDRESS_SPACE_CONSTRAINED)
endif() endif()
@@ -174,6 +179,9 @@ if(NOT DEFINED SNMALLOC_ONLY_HEADER_LIBRARY)
if (${TEST_CATEGORY} MATCHES "perf") if (${TEST_CATEGORY} MATCHES "perf")
set_tests_properties(${TESTNAME} PROPERTIES PROCESSORS 4) set_tests_properties(${TESTNAME} PROPERTIES PROCESSORS 4)
endif() endif()
if (${TEST_CATEGORY} MATCHES "func")
target_compile_definitions(${TESTNAME} PRIVATE -DUSE_SNMALLOC_STATS)
endif ()
endforeach() endforeach()
endforeach() endforeach()
endforeach() endforeach()

View File

@@ -72,9 +72,9 @@ jobs:
displayName: 'Install Build Dependencies' displayName: 'Install Build Dependencies'
- task: CMake@1 - task: CMake@1
displayName: 'CMake .. $(CMakeArgs) -GNinja -DCMAKE_BUILD_TYPE=$(BuildType) -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS"' displayName: 'CMake .. $(CMakeArgs) -GNinja -DCMAKE_BUILD_TYPE=$(BuildType) -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS" -DSNMALLOC_CI_BUILD=On'
inputs: inputs:
cmakeArgs: '.. $(CMakeArgs) -GNinja -DCMAKE_BUILD_TYPE=$(BuildType) -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS"' cmakeArgs: '.. $(CMakeArgs) -GNinja -DCMAKE_BUILD_TYPE=$(BuildType) -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS" -DSNMALLOC_CI_BUILD=On'
- script: | - script: |
ninja ninja
@@ -131,9 +131,9 @@ jobs:
steps: steps:
- task: CMake@1 - task: CMake@1
displayName: 'CMake .. $(CMakeArgs) -DCMAKE_BUILD_TYPE=$(BuildType)' displayName: 'CMake .. $(CMakeArgs) -DCMAKE_BUILD_TYPE=$(BuildType) -DSNMALLOC_CI_BUILD=On'
inputs: inputs:
cmakeArgs: '.. $(CMakeArgs) -DCMAKE_BUILD_TYPE=$(BuildType)' cmakeArgs: '.. $(CMakeArgs) -DCMAKE_BUILD_TYPE=$(BuildType) -DSNMALLOC_CI_BUILD=On'
- task: MSBuild@1 - task: MSBuild@1
displayName: 'Build solution build/snmalloc.sln' displayName: 'Build solution build/snmalloc.sln'
@@ -158,9 +158,9 @@ jobs:
steps: steps:
- task: CMake@1 - task: CMake@1
displayName: 'CMake .. -DCMAKE_BUILD_TYPE=$(BuildType)' displayName: 'CMake .. -DCMAKE_BUILD_TYPE=$(BuildType) -DSNMALLOC_CI_BUILD=On'
inputs: inputs:
cmakeArgs: '.. -DCMAKE_BUILD_TYPE=$(BuildType)' cmakeArgs: '.. -DCMAKE_BUILD_TYPE=$(BuildType) -DSNMALLOC_CI_BUILD=On'
- script: | - script: |
make -j 4 make -j 4

View File

@@ -1084,13 +1084,13 @@ namespace snmalloc
SNMALLOC_ASSUME(size <= SLAB_SIZE); SNMALLOC_ASSUME(size <= SLAB_SIZE);
sizeclass_t sizeclass = size_to_sizeclass(size); sizeclass_t sizeclass = size_to_sizeclass(size);
stats().sizeclass_alloc(sizeclass);
assert(sizeclass < NUM_SMALL_CLASSES); assert(sizeclass < NUM_SMALL_CLASSES);
auto& fl = small_fast_free_lists[sizeclass]; auto& fl = small_fast_free_lists[sizeclass];
void* head = fl.value; void* head = fl.value;
if (likely(head != nullptr)) if (likely(head != nullptr))
{ {
stats().sizeclass_alloc(sizeclass);
// Read the next slot from the memory that's about to be allocated. // Read the next slot from the memory that's about to be allocated.
fl.value = Metaslab::follow_next(head); fl.value = Metaslab::follow_next(head);
@@ -1113,6 +1113,9 @@ namespace snmalloc
return reinterpret_cast<Allocator*>(replacement) return reinterpret_cast<Allocator*>(replacement)
->template small_alloc_slow<zero_mem, allow_reserve>(sizeclass); ->template small_alloc_slow<zero_mem, allow_reserve>(sizeclass);
} }
stats().sizeclass_alloc(sizeclass);
handle_message_queue(); handle_message_queue();
size_t rsize = sizeclass_to_size(sizeclass); size_t rsize = sizeclass_to_size(sizeclass);
auto& sl = small_classes[sizeclass]; auto& sl = small_classes[sizeclass];

View File

@@ -141,7 +141,9 @@ namespace snmalloc
UNUSED(size); UNUSED(size);
#ifdef USE_SNMALLOC_STATS #ifdef USE_SNMALLOC_STATS
bucketed_requests[bits::to_exp_mant<BUCKETS_BITS>(size)]++; auto index = (size == 0) ? 0 : bits::to_exp_mant<BUCKETS_BITS>(size);
assert(index < TOTAL_BUCKETS);
bucketed_requests[index]++;
#endif #endif
} }

View File

@@ -107,28 +107,26 @@ namespace snmalloc
#endif #endif
} }
void debug_check_empty() /**
If you pass a pointer to a bool, then it returns whether all the
allocators are empty. If you don't pass a pointer to a bool, then will
raise an error all the allocators are not empty.
*/
void debug_check_empty(bool* result = nullptr)
{ {
#ifndef USE_MALLOC #ifndef USE_MALLOC
// This is a debugging function. It checks that all memory from all // This is a debugging function. It checks that all memory from all
// allocators has been freed. // allocators has been freed.
size_t alloc_count = 0;
auto* alloc = Parent::iterate(); auto* alloc = Parent::iterate();
// Count the linked allocators.
while (alloc != nullptr)
{
alloc = Parent::iterate(alloc);
alloc_count++;
}
bool done = false; bool done = false;
size_t non_empty_count = 0;
while (!done) while (!done)
{ {
done = true; done = true;
alloc = Parent::iterate(); alloc = Parent::iterate();
non_empty_count = 0;
while (alloc != nullptr) while (alloc != nullptr)
{ {
@@ -142,6 +140,10 @@ namespace snmalloc
p = next; p = next;
} }
// Check that the allocator has freed all memory.
if (!alloc->stats().is_empty())
non_empty_count++;
// Place the static stub message on the queue. // Place the static stub message on the queue.
alloc->init_message_queue(); alloc->init_message_queue();
@@ -158,20 +160,16 @@ namespace snmalloc
} }
} }
alloc = Parent::iterate(); if (result != nullptr)
size_t empty_count = 0;
while (alloc != nullptr)
{ {
// Check that the allocator has freed all memory. *result = non_empty_count == 0;
if (alloc->stats().is_empty()) return;
empty_count++;
alloc = Parent::iterate(alloc);
} }
if (alloc_count != empty_count) if (non_empty_count != 0)
error("Incorrect number of allocators"); {
error("debug_check_empty: found non-empty allocators");
}
#endif #endif
} }
}; };

View File

@@ -1,4 +1,5 @@
#include <stdio.h> #include <stdio.h>
#include <test/setup.h>
#define SNMALLOC_NAME_MANGLE(a) our_##a #define SNMALLOC_NAME_MANGLE(a) our_##a
#include "../../../override/malloc.cc" #include "../../../override/malloc.cc"
@@ -48,8 +49,11 @@ void test_realloc(void* p, size_t size, int err, bool null)
{ {
fprintf(stderr, "realloc(%p(%d), %d)\n", p, int(size), (int)size); fprintf(stderr, "realloc(%p(%d), %d)\n", p, int(size), (int)size);
errno = 0; errno = 0;
p = our_realloc(p, size); auto new_p = our_realloc(p, size);
check_result(size, 1, p, err, null); // Realloc failure case, deallocate original block
if (new_p == nullptr && size != 0)
our_free(p);
check_result(size, 1, new_p, err, null);
} }
void test_posix_memalign(size_t size, size_t align, int err, bool null) void test_posix_memalign(size_t size, size_t align, int err, bool null)
@@ -73,6 +77,8 @@ int main(int argc, char** argv)
UNUSED(argc); UNUSED(argc);
UNUSED(argv); UNUSED(argv);
setup();
constexpr int SUCCESS = 0; constexpr int SUCCESS = 0;
test_calloc(0, 0, SUCCESS, false); test_calloc(0, 0, SUCCESS, false);
@@ -115,5 +121,6 @@ int main(int argc, char** argv)
test_posix_memalign(0, align + 1, EINVAL, true); test_posix_memalign(0, align + 1, EINVAL, true);
} }
current_alloc_pool()->debug_check_empty();
return 0; return 0;
} }

View File

@@ -1,4 +1,5 @@
#include <snmalloc.h> #include <snmalloc.h>
#include <test/setup.h>
using namespace snmalloc; using namespace snmalloc;
@@ -9,6 +10,8 @@ using namespace snmalloc;
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
setup();
UNUSED(argc); UNUSED(argc);
UNUSED(argv); UNUSED(argv);

View File

@@ -1,5 +1,6 @@
#include <iostream> #include <iostream>
#include <snmalloc.h> #include <snmalloc.h>
#include <test/setup.h>
NOINLINE NOINLINE
snmalloc::sizeclass_t size_to_sizeclass(size_t size) snmalloc::sizeclass_t size_to_sizeclass(size_t size)
@@ -9,6 +10,8 @@ snmalloc::sizeclass_t size_to_sizeclass(size_t size)
int main(int, char**) int main(int, char**)
{ {
setup();
bool failed = false; bool failed = false;
size_t size_low = 0; size_t size_low = 0;

View File

@@ -0,0 +1,39 @@
#include <snmalloc.h>
int main()
{
snmalloc::Alloc* a = snmalloc::ThreadAlloc::get();
bool result;
auto r = a->alloc(16);
snmalloc::current_alloc_pool()->debug_check_empty(&result);
if (result != false)
{
abort();
}
a->dealloc(r);
snmalloc::current_alloc_pool()->debug_check_empty(&result);
if (result != true)
{
abort();
}
r = a->alloc(16);
snmalloc::current_alloc_pool()->debug_check_empty(&result);
if (result != false)
{
abort();
}
a->dealloc(r);
snmalloc::current_alloc_pool()->debug_check_empty(&result);
if (result != true)
{
abort();
}
}

View File

@@ -3,6 +3,7 @@
#include <iostream> #include <iostream>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <test/setup.h>
void* oe_base; void* oe_base;
void* oe_end; void* oe_end;
@@ -40,9 +41,11 @@ host_snmalloc_pagemap_global_get(snmalloc::PagemapConfig const**);
using namespace snmalloc; using namespace snmalloc;
int main() int main()
{ {
setup();
MemoryProviderStateMixin<DefaultPal> mp; MemoryProviderStateMixin<DefaultPal> mp;
size_t size = 1ULL << 28; size_t size = 1ULL << 26;
oe_base = mp.reserve<true>(&size, 1); oe_base = mp.reserve<true>(&size, 1);
oe_end = (uint8_t*)oe_base + size; oe_end = (uint8_t*)oe_base + size;
std::cout << "Allocated region " << oe_base << " - " << oe_end << std::endl; std::cout << "Allocated region " << oe_base << " - " << oe_end << std::endl;

View File

@@ -1,5 +1,6 @@
#include "test/measuretime.h" #include "test/measuretime.h"
#include "test/opt.h" #include "test/opt.h"
#include "test/setup.h"
#include "test/usage.h" #include "test/usage.h"
#include "test/xoroshiro.h" #include "test/xoroshiro.h"
@@ -148,6 +149,8 @@ void test_tasks(size_t num_tasks, size_t count, size_t size)
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
setup();
opt::Opt opt(argc, argv); opt::Opt opt(argc, argv);
size_t cores = opt.is<size_t>("--cores", 8); size_t cores = opt.is<size_t>("--cores", 8);

View File

@@ -1,5 +1,6 @@
#include <snmalloc.h> #include <snmalloc.h>
#include <test/measuretime.h> #include <test/measuretime.h>
#include <test/setup.h>
#include <test/xoroshiro.h> #include <test/xoroshiro.h>
#include <unordered_set> #include <unordered_set>
@@ -78,6 +79,8 @@ namespace test
int main(int, char**) int main(int, char**)
{ {
setup();
xoroshiro::p128r64 r; xoroshiro::p128r64 r;
#if NDEBUG #if NDEBUG
size_t nn = 30; size_t nn = 30;

View File

@@ -1,5 +1,6 @@
#include <snmalloc.h> #include <snmalloc.h>
#include <test/measuretime.h> #include <test/measuretime.h>
#include <test/setup.h>
#include <unordered_set> #include <unordered_set>
using namespace snmalloc; using namespace snmalloc;
@@ -63,6 +64,8 @@ void test_alloc_dealloc(size_t count, size_t size, bool write)
int main(int, char**) int main(int, char**)
{ {
setup();
for (size_t size = 16; size <= 128; size <<= 1) for (size_t size = 16; size <= 128; size <<= 1)
{ {
test_alloc_dealloc<NoZero>(1 << 15, size, false); test_alloc_dealloc<NoZero>(1 << 15, size, false);

20
src/test/setup.h Normal file
View File

@@ -0,0 +1,20 @@
#if defined(WIN32) && defined(SNMALLOC_CI_BUILD)
# include <ds/bits.h>
# include <signal.h>
# include <stdlib.h>
void _cdecl error(int signal)
{
UNUSED(signal);
puts("*****ABORT******");
_exit(1);
}
void setup()
{
// Disable abort dialog box in CI builds.
_set_error_mode(_OUT_TO_STDERR);
_set_abort_behavior(0, _WRITE_ABORT_MSG);
signal(SIGABRT, error);
}
#else
void setup() {}
#endif