From d7105c20a9020116bd5bdbacaa61e9458f53ea52 Mon Sep 17 00:00:00 2001 From: Frank Richter Date: Tue, 21 Dec 2021 12:39:17 +0100 Subject: [PATCH 01/10] Move test macros/helpers to a separate header --- test/test-api.c | 34 ++------------------------------ test/testhelper.h | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 32 deletions(-) create mode 100644 test/testhelper.h diff --git a/test/test-api.c b/test/test-api.c index f057799a..8ecd31a1 100644 --- a/test/test-api.c +++ b/test/test-api.c @@ -23,7 +23,6 @@ we therefore test the API over various inputs. Please add more tests :-) [1] https://github.com/daanx/mimalloc-bench */ -#include #include #include #include @@ -36,33 +35,7 @@ we therefore test the API over various inputs. Please add more tests :-) #include "mimalloc.h" // #include "mimalloc-internal.h" -// --------------------------------------------------------------------------- -// Test macros: CHECK(name,predicate) and CHECK_BODY(name,body) -// --------------------------------------------------------------------------- -static int ok = 0; -static int failed = 0; - -#define CHECK_BODY(name,body) \ - do { \ - fprintf(stderr,"test: %s... ", name ); \ - bool result = true; \ - do { body } while(false); \ - if (!(result)) { \ - failed++; \ - fprintf(stderr, \ - "\n FAILED: %s:%d:\n %s\n", \ - __FILE__, \ - __LINE__, \ - #body); \ - /* exit(1); */ \ - } \ - else { \ - ok++; \ - fprintf(stderr,"ok.\n"); \ - } \ - } while (false) - -#define CHECK(name,expr) CHECK_BODY(name,{ result = (expr); }) +#include "testhelper.h" // --------------------------------------------------------------------------- // Test functions @@ -219,10 +192,7 @@ int main(void) { // --------------------------------------------------- // Done // ---------------------------------------------------[] - fprintf(stderr,"\n\n---------------------------------------------\n" - "succeeded: %i\n" - "failed : %i\n\n", ok, failed); - return failed; + return print_test_summary(); } // --------------------------------------------------- diff --git a/test/testhelper.h b/test/testhelper.h new file mode 100644 index 00000000..46d63a00 --- /dev/null +++ b/test/testhelper.h @@ -0,0 +1,49 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2018-2020, Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ +#ifndef TESTHELPER_H_ +#define TESTHELPER_H_ + +#include + +// --------------------------------------------------------------------------- +// Test macros: CHECK(name,predicate) and CHECK_BODY(name,body) +// --------------------------------------------------------------------------- +static int ok = 0; +static int failed = 0; + +#define CHECK_BODY(name,body) \ + do { \ + fprintf(stderr,"test: %s... ", name ); \ + bool result = true; \ + do { body } while(false); \ + if (!(result)) { \ + failed++; \ + fprintf(stderr, \ + "\n FAILED: %s:%d:\n %s\n", \ + __FILE__, \ + __LINE__, \ + #body); \ + /* exit(1); */ \ + } \ + else { \ + ok++; \ + fprintf(stderr,"ok.\n"); \ + } \ + } while (false) + +#define CHECK(name,expr) CHECK_BODY(name,{ result = (expr); }) + +// Print summary of test. Return value can be directly use as a return value for main(). +static inline int print_test_summary(void) +{ + fprintf(stderr,"\n\n---------------------------------------------\n" + "succeeded: %i\n" + "failed : %i\n\n", ok, failed); + return failed; +} + +#endif // TESTHELPER_H_ From 51271ba8ea47e250d22fe6b7a2f6813c07336cca Mon Sep 17 00:00:00 2001 From: Frank Richter Date: Tue, 21 Dec 2021 12:54:15 +0100 Subject: [PATCH 02/10] Replace redundant CMake code for tests with a loop --- CMakeLists.txt | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d52a72d..5a682bf7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -373,21 +373,17 @@ endif() # ----------------------------------------------------------------------------- if (MI_BUILD_TESTS) - add_executable(mimalloc-test-api test/test-api.c) - target_compile_definitions(mimalloc-test-api PRIVATE ${mi_defines}) - target_compile_options(mimalloc-test-api PRIVATE ${mi_cflags}) - target_include_directories(mimalloc-test-api PRIVATE include) - target_link_libraries(mimalloc-test-api PRIVATE mimalloc ${mi_libraries}) - - add_executable(mimalloc-test-stress test/test-stress.c) - target_compile_definitions(mimalloc-test-stress PRIVATE ${mi_defines}) - target_compile_options(mimalloc-test-stress PRIVATE ${mi_cflags}) - target_include_directories(mimalloc-test-stress PRIVATE include) - target_link_libraries(mimalloc-test-stress PRIVATE mimalloc ${mi_libraries}) - enable_testing() - add_test(test_api, mimalloc-test-api) - add_test(test_stress, mimalloc-test-stress) + + foreach(TEST_NAME api stress) + add_executable(mimalloc-test-${TEST_NAME} test/test-${TEST_NAME}.c) + target_compile_definitions(mimalloc-test-${TEST_NAME} PRIVATE ${mi_defines}) + target_compile_options(mimalloc-test-${TEST_NAME} PRIVATE ${mi_cflags}) + target_include_directories(mimalloc-test-${TEST_NAME} PRIVATE include) + target_link_libraries(mimalloc-test-${TEST_NAME} PRIVATE mimalloc ${mi_libraries}) + + add_test(NAME test-${TEST_NAME} COMMAND mimalloc-test-${TEST_NAME}) + endforeach() endif() # ----------------------------------------------------------------------------- From 969f3a6998c194d3f359072e5e6067b1581965e7 Mon Sep 17 00:00:00 2001 From: Frank Richter Date: Sun, 19 Dec 2021 19:45:39 +0100 Subject: [PATCH 03/10] Add tests for zero-initialization functions --- CMakeLists.txt | 2 +- test/test-api-fill.c | 180 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 test/test-api-fill.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a682bf7..47366c49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -375,7 +375,7 @@ endif() if (MI_BUILD_TESTS) enable_testing() - foreach(TEST_NAME api stress) + foreach(TEST_NAME api api-fill stress) add_executable(mimalloc-test-${TEST_NAME} test/test-${TEST_NAME}.c) target_compile_definitions(mimalloc-test-${TEST_NAME} PRIVATE ${mi_defines}) target_compile_options(mimalloc-test-${TEST_NAME} PRIVATE ${mi_cflags}) diff --git a/test/test-api-fill.c b/test/test-api-fill.c new file mode 100644 index 00000000..404dcb7f --- /dev/null +++ b/test/test-api-fill.c @@ -0,0 +1,180 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2018-2020, Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ +#include "mimalloc.h" +#include "mimalloc-types.h" + +#include "testhelper.h" + +// --------------------------------------------------------------------------- +// Helper functions +// --------------------------------------------------------------------------- +bool check_zero_init(uint8_t* p, size_t size); + +// --------------------------------------------------------------------------- +// Main testing +// --------------------------------------------------------------------------- +int main(void) { + mi_option_disable(mi_option_verbose); + + // --------------------------------------------------- + // Zeroing allocation + // --------------------------------------------------- + CHECK_BODY("zeroinit-zalloc-small", { + size_t zalloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_zalloc(zalloc_size); + result = check_zero_init(p, zalloc_size); + mi_free(p); + }); + CHECK_BODY("zeroinit-zalloc-large", { + size_t zalloc_size = MI_SMALL_SIZE_MAX * 2; + uint8_t* p = (uint8_t*)mi_zalloc(zalloc_size); + result = check_zero_init(p, zalloc_size); + mi_free(p); + }); + CHECK_BODY("zeroinit-zalloc_small", { + size_t zalloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_zalloc_small(zalloc_size); + result = check_zero_init(p, zalloc_size); + mi_free(p); + }); + + CHECK_BODY("zeroinit-calloc-small", { + size_t calloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_calloc(calloc_size, 1); + result = check_zero_init(p, calloc_size); + mi_free(p); + }); + CHECK_BODY("zeroinit-calloc-large", { + size_t calloc_size = MI_SMALL_SIZE_MAX * 2; + uint8_t* p = (uint8_t*)mi_calloc(calloc_size, 1); + result = check_zero_init(p, calloc_size); + mi_free(p); + }); + + CHECK_BODY("zeroinit-rezalloc-small", { + size_t zalloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_zalloc(zalloc_size); + result = check_zero_init(p, zalloc_size); + zalloc_size *= 3; + p = (uint8_t*)mi_rezalloc(p, zalloc_size); + result &= check_zero_init(p, zalloc_size); + mi_free(p); + }); + CHECK_BODY("zeroinit-rezalloc-large", { + size_t zalloc_size = MI_SMALL_SIZE_MAX * 2; + uint8_t* p = (uint8_t*)mi_zalloc(zalloc_size); + result = check_zero_init(p, zalloc_size); + zalloc_size *= 3; + p = (uint8_t*)mi_rezalloc(p, zalloc_size); + result &= check_zero_init(p, zalloc_size); + mi_free(p); + }); + + CHECK_BODY("zeroinit-recalloc-small", { + size_t calloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_calloc(calloc_size, 1); + result = check_zero_init(p, calloc_size); + calloc_size *= 3; + p = (uint8_t*)mi_recalloc(p, calloc_size, 1); + result &= check_zero_init(p, calloc_size); + mi_free(p); + }); + CHECK_BODY("zeroinit-recalloc-large", { + size_t calloc_size = MI_SMALL_SIZE_MAX * 2; + uint8_t* p = (uint8_t*)mi_calloc(calloc_size, 1); + result = check_zero_init(p, calloc_size); + calloc_size *= 3; + p = (uint8_t*)mi_recalloc(p, calloc_size, 1); + result &= check_zero_init(p, calloc_size); + mi_free(p); + }); + + // --------------------------------------------------- + // Zeroing in aligned API + // --------------------------------------------------- + CHECK_BODY("zeroinit-zalloc_aligned-small", { + size_t zalloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_zalloc_aligned(zalloc_size, MI_MAX_ALIGN_SIZE * 2); + result = check_zero_init(p, zalloc_size); + mi_free(p); + }); + CHECK_BODY("zeroinit-zalloc_aligned-large", { + size_t zalloc_size = MI_SMALL_SIZE_MAX * 2; + uint8_t* p = (uint8_t*)mi_zalloc_aligned(zalloc_size, MI_MAX_ALIGN_SIZE * 2); + result = check_zero_init(p, zalloc_size); + mi_free(p); + }); + + CHECK_BODY("zeroinit-calloc_aligned-small", { + size_t calloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_calloc_aligned(calloc_size, 1, MI_MAX_ALIGN_SIZE * 2); + result = check_zero_init(p, calloc_size); + mi_free(p); + }); + CHECK_BODY("zeroinit-calloc_aligned-large", { + size_t calloc_size = MI_SMALL_SIZE_MAX * 2; + uint8_t* p = (uint8_t*)mi_calloc_aligned(calloc_size, 1, MI_MAX_ALIGN_SIZE * 2); + result = check_zero_init(p, calloc_size); + mi_free(p); + }); + + CHECK_BODY("zeroinit-rezalloc_aligned-small", { + size_t zalloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_zalloc_aligned(zalloc_size, MI_MAX_ALIGN_SIZE * 2); + result = check_zero_init(p, zalloc_size); + zalloc_size *= 3; + p = (uint8_t*)mi_rezalloc_aligned(p, zalloc_size, MI_MAX_ALIGN_SIZE * 2); + result &= check_zero_init(p, zalloc_size); + mi_free(p); + }); + CHECK_BODY("zeroinit-rezalloc_aligned-large", { + size_t zalloc_size = MI_SMALL_SIZE_MAX * 2; + uint8_t* p = (uint8_t*)mi_zalloc_aligned(zalloc_size, MI_MAX_ALIGN_SIZE * 2); + result = check_zero_init(p, zalloc_size); + zalloc_size *= 3; + p = (uint8_t*)mi_rezalloc_aligned(p, zalloc_size, MI_MAX_ALIGN_SIZE * 2); + result &= check_zero_init(p, zalloc_size); + mi_free(p); + }); + + CHECK_BODY("zeroinit-recalloc_aligned-small", { + size_t calloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_calloc_aligned(calloc_size, 1, MI_MAX_ALIGN_SIZE * 2); + result = check_zero_init(p, calloc_size); + calloc_size *= 3; + p = (uint8_t*)mi_recalloc_aligned(p, calloc_size, 1, MI_MAX_ALIGN_SIZE * 2); + result &= check_zero_init(p, calloc_size); + mi_free(p); + }); + CHECK_BODY("zeroinit-recalloc_aligned-large", { + size_t calloc_size = MI_SMALL_SIZE_MAX * 2; + uint8_t* p = (uint8_t*)mi_calloc_aligned(calloc_size, 1, MI_MAX_ALIGN_SIZE * 2); + result = check_zero_init(p, calloc_size); + calloc_size *= 3; + p = (uint8_t*)mi_recalloc_aligned(p, calloc_size, 1, MI_MAX_ALIGN_SIZE * 2); + result &= check_zero_init(p, calloc_size); + mi_free(p); + }); + + // --------------------------------------------------- + // Done + // ---------------------------------------------------[] + return print_test_summary(); +} + +// --------------------------------------------------------------------------- +// Helper functions +// --------------------------------------------------------------------------- +bool check_zero_init(uint8_t* p, size_t size) { + if(!p) + return false; + bool result = true; + for (size_t i = 0; i < size; ++i) { + result &= p[i] == 0; + } + return result; +} From 1cf7ca021da6535df41746b3d9445571c7a0ebc2 Mon Sep 17 00:00:00 2001 From: Frank Richter Date: Sun, 19 Dec 2021 21:56:52 +0100 Subject: [PATCH 04/10] Add tests for debug mode "uninit fill" behaviour --- test/test-api-fill.c | 124 +++++++++++++++++++++++++++++++++++++++++++ test/test-api.c | 1 + 2 files changed, 125 insertions(+) diff --git a/test/test-api-fill.c b/test/test-api-fill.c index 404dcb7f..39f6f881 100644 --- a/test/test-api-fill.c +++ b/test/test-api-fill.c @@ -13,6 +13,9 @@ terms of the MIT license. A copy of the license can be found in the file // Helper functions // --------------------------------------------------------------------------- bool check_zero_init(uint8_t* p, size_t size); +#if MI_DEBUG >= 2 +bool check_debug_fill_uninit(uint8_t* p, size_t size); +#endif // --------------------------------------------------------------------------- // Main testing @@ -160,6 +163,114 @@ int main(void) { mi_free(p); }); +#if MI_DEBUG >= 2 + // --------------------------------------------------- + // Debug filling + // --------------------------------------------------- + CHECK_BODY("uninit-malloc-small", { + size_t malloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_malloc(malloc_size); + result = check_debug_fill_uninit(p, malloc_size); + mi_free(p); + }); + CHECK_BODY("uninit-malloc-large", { + size_t malloc_size = MI_SMALL_SIZE_MAX * 2; + uint8_t* p = (uint8_t*)mi_malloc(malloc_size); + result = check_debug_fill_uninit(p, malloc_size); + mi_free(p); + }); + + CHECK_BODY("uninit-malloc_small", { + size_t malloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_malloc_small(malloc_size); + result = check_debug_fill_uninit(p, malloc_size); + mi_free(p); + }); + + CHECK_BODY("uninit-realloc-small", { + size_t malloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_malloc(malloc_size); + result = check_debug_fill_uninit(p, malloc_size); + malloc_size *= 3; + p = (uint8_t*)mi_realloc(p, malloc_size); + result &= check_debug_fill_uninit(p, malloc_size); + mi_free(p); + }); + CHECK_BODY("uninit-realloc-large", { + size_t malloc_size = MI_SMALL_SIZE_MAX * 2; + uint8_t* p = (uint8_t*)mi_malloc(malloc_size); + result = check_debug_fill_uninit(p, malloc_size); + malloc_size *= 3; + p = (uint8_t*)mi_realloc(p, malloc_size); + result &= check_debug_fill_uninit(p, malloc_size); + mi_free(p); + }); + + CHECK_BODY("uninit-mallocn-small", { + size_t malloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_mallocn(malloc_size, 1); + result = check_debug_fill_uninit(p, malloc_size); + mi_free(p); + }); + CHECK_BODY("uninit-mallocn-large", { + size_t malloc_size = MI_SMALL_SIZE_MAX * 2; + uint8_t* p = (uint8_t*)mi_mallocn(malloc_size, 1); + result = check_debug_fill_uninit(p, malloc_size); + mi_free(p); + }); + + CHECK_BODY("uninit-reallocn-small", { + size_t malloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_mallocn(malloc_size, 1); + result = check_debug_fill_uninit(p, malloc_size); + malloc_size *= 3; + p = (uint8_t*)mi_reallocn(p, malloc_size, 1); + result &= check_debug_fill_uninit(p, malloc_size); + mi_free(p); + }); + CHECK_BODY("uninit-reallocn-large", { + size_t malloc_size = MI_SMALL_SIZE_MAX * 2; + uint8_t* p = (uint8_t*)mi_mallocn(malloc_size, 1); + result = check_debug_fill_uninit(p, malloc_size); + malloc_size *= 3; + p = (uint8_t*)mi_reallocn(p, malloc_size, 1); + result &= check_debug_fill_uninit(p, malloc_size); + mi_free(p); + }); + + CHECK_BODY("uninit-malloc_aligned-small", { + size_t malloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_malloc_aligned(malloc_size, MI_MAX_ALIGN_SIZE * 2); + result = check_debug_fill_uninit(p, malloc_size); + mi_free(p); + }); + CHECK_BODY("uninit-malloc_aligned-large", { + size_t malloc_size = MI_SMALL_SIZE_MAX * 2; + uint8_t* p = (uint8_t*)mi_malloc_aligned(malloc_size, MI_MAX_ALIGN_SIZE * 2); + result = check_debug_fill_uninit(p, malloc_size); + mi_free(p); + }); + + CHECK_BODY("uninit-realloc_aligned-small", { + size_t malloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_malloc_aligned(malloc_size, MI_MAX_ALIGN_SIZE * 2); + result = check_debug_fill_uninit(p, malloc_size); + malloc_size *= 3; + p = (uint8_t*)mi_realloc_aligned(p, malloc_size, MI_MAX_ALIGN_SIZE * 2); + result &= check_debug_fill_uninit(p, malloc_size); + mi_free(p); + }); + CHECK_BODY("uninit-realloc_aligned-large", { + size_t malloc_size = MI_SMALL_SIZE_MAX * 2; + uint8_t* p = (uint8_t*)mi_malloc_aligned(malloc_size, MI_MAX_ALIGN_SIZE * 2); + result = check_debug_fill_uninit(p, malloc_size); + malloc_size *= 3; + p = (uint8_t*)mi_realloc_aligned(p, malloc_size, MI_MAX_ALIGN_SIZE * 2); + result &= check_debug_fill_uninit(p, malloc_size); + mi_free(p); + }); +#endif + // --------------------------------------------------- // Done // ---------------------------------------------------[] @@ -178,3 +289,16 @@ bool check_zero_init(uint8_t* p, size_t size) { } return result; } + +#if MI_DEBUG >= 2 +bool check_debug_fill_uninit(uint8_t* p, size_t size) { + if(!p) + return false; + + bool result = true; + for (size_t i = 0; i < size; ++i) { + result &= p[i] == MI_DEBUG_UNINIT; + } + return result; +} +#endif diff --git a/test/test-api.c b/test/test-api.c index 8ecd31a1..7ce6f111 100644 --- a/test/test-api.c +++ b/test/test-api.c @@ -34,6 +34,7 @@ we therefore test the API over various inputs. Please add more tests :-) #include "mimalloc.h" // #include "mimalloc-internal.h" +#include "mimalloc-types.h" // for MI_DEBUG #include "testhelper.h" From 691eb0d8edc17fbb4850a704244fed302282f931 Mon Sep 17 00:00:00 2001 From: Frank Richter Date: Sun, 19 Dec 2021 21:57:06 +0100 Subject: [PATCH 05/10] Add tests to check "freed memory fill" behaviour in debug mode --- test/test-api-fill.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/test-api-fill.c b/test/test-api-fill.c index 39f6f881..0e5a65dc 100644 --- a/test/test-api-fill.c +++ b/test/test-api-fill.c @@ -15,6 +15,7 @@ terms of the MIT license. A copy of the license can be found in the file bool check_zero_init(uint8_t* p, size_t size); #if MI_DEBUG >= 2 bool check_debug_fill_uninit(uint8_t* p, size_t size); +bool check_debug_fill_freed(uint8_t* p, size_t size); #endif // --------------------------------------------------------------------------- @@ -269,6 +270,22 @@ int main(void) { result &= check_debug_fill_uninit(p, malloc_size); mi_free(p); }); + + + CHECK_BODY("fill-freed-small", { + size_t malloc_size = MI_SMALL_SIZE_MAX / 2; + uint8_t* p = (uint8_t*)mi_malloc(malloc_size); + mi_free(p); + // First sizeof(void*) bytes will contain housekeeping data, skip these + result = check_debug_fill_freed(p + sizeof(void*), malloc_size - sizeof(void*)); + }); + CHECK_BODY("fill-freed-large", { + size_t malloc_size = MI_SMALL_SIZE_MAX * 2; + uint8_t* p = (uint8_t*)mi_malloc(malloc_size); + mi_free(p); + // First sizeof(void*) bytes will contain housekeeping data, skip these + result = check_debug_fill_freed(p + sizeof(void*), malloc_size - sizeof(void*)); + }); #endif // --------------------------------------------------- @@ -301,4 +318,15 @@ bool check_debug_fill_uninit(uint8_t* p, size_t size) { } return result; } + +bool check_debug_fill_freed(uint8_t* p, size_t size) { + if(!p) + return false; + + bool result = true; + for (size_t i = 0; i < size; ++i) { + result &= p[i] == MI_DEBUG_FREED; + } + return result; +} #endif From 164b3a9667f472367f84851cfabc87ab08df26f6 Mon Sep 17 00:00:00 2001 From: Frank Richter Date: Tue, 21 Dec 2021 13:07:39 +0100 Subject: [PATCH 06/10] Pass build config to CMake invocation in Windows pipeline jobs --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8bd51ab0..cfaf1876 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -43,7 +43,7 @@ jobs: solution: $(BuildType)/libmimalloc.sln configuration: '$(MSBuildConfiguration)' msbuildArguments: -m - - script: ctest --verbose --timeout 120 + - script: ctest --verbose --timeout 120 -C $(MSBuildConfiguration) workingDirectory: $(BuildType) displayName: CTest #- script: $(BuildType)\$(BuildType)\mimalloc-test-stress From d24262f4773ff3ef0308665c332107c5c01d3dcd Mon Sep 17 00:00:00 2001 From: Frank Richter Date: Tue, 28 Dec 2021 14:54:15 +0100 Subject: [PATCH 07/10] Prefer MSVC 'data section magic' over C++ static initialization --- src/init.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/init.c b/src/init.c index e06fa6b9..25de0301 100644 --- a/src/init.c +++ b/src/init.c @@ -557,20 +557,6 @@ static void mi_process_done(void) { return TRUE; } -#elif defined(__cplusplus) - // C++: use static initialization to detect process start - static bool _mi_process_init(void) { - mi_process_load(); - return (_mi_heap_main.thread_id != 0); - } - static bool mi_initialized = _mi_process_init(); - -#elif defined(__GNUC__) || defined(__clang__) - // GCC,Clang: use the constructor attribute - static void __attribute__((constructor)) _mi_process_init(void) { - mi_process_load(); - } - #elif defined(_MSC_VER) // MSVC: use data section magic for static libraries // See @@ -586,9 +572,23 @@ static void mi_process_done(void) { __pragma(comment(linker, "/include:" "__mi_msvc_initu")) #endif #pragma data_seg(".CRT$XIU") - _crt_cb _mi_msvc_initu[] = { &_mi_process_init }; + extern "C" _crt_cb _mi_msvc_initu[] = { &_mi_process_init }; #pragma data_seg() +#elif defined(__cplusplus) + // C++: use static initialization to detect process start + static bool _mi_process_init(void) { + mi_process_load(); + return (_mi_heap_main.thread_id != 0); + } + static bool mi_initialized = _mi_process_init(); + +#elif defined(__GNUC__) || defined(__clang__) + // GCC,Clang: use the constructor attribute + static void __attribute__((constructor)) _mi_process_init(void) { + mi_process_load(); + } + #else #pragma message("define a way to call mi_process_load on your platform") #endif From f456bc75ead42e71680fc6d1111ffa16e85b1425 Mon Sep 17 00:00:00 2001 From: Frank Richter Date: Tue, 28 Dec 2021 14:59:32 +0100 Subject: [PATCH 08/10] Perform thread cleanup for main threads as late as possible for Windows static builds --- src/init.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/init.c b/src/init.c index 25de0301..47aa2b23 100644 --- a/src/init.c +++ b/src/init.c @@ -493,6 +493,11 @@ void mi_process_init(void) mi_attr_noexcept { #endif _mi_verbose_message("secure level: %d\n", MI_SECURE); mi_thread_init(); +#if defined(_WIN32) && !defined(MI_SHARED_LIB) + // When building as a static lib FLS cleanup happens to early for the main thread. + // Make it a no-op and perform it explicitly later. + FlsSetValue(mi_fls_key, NULL); +#endif mi_stats_reset(); // only call stat reset *after* thread init (or the heap tld == NULL) if (mi_option_is_enabled(mi_option_reserve_huge_os_pages)) { @@ -522,6 +527,8 @@ static void mi_process_done(void) { process_done = true; #if defined(_WIN32) && !defined(MI_SHARED_LIB) + // Explicitly clean up main thread + _mi_thread_done(_mi_heap_default); FlsSetValue(mi_fls_key, NULL); // don't call main-thread callback FlsFree(mi_fls_key); // call thread-done on all threads to prevent dangling callback pointer if statically linked with a DLL; Issue #208 #endif From 2b1990805745dad1a7f85c5aa17c2d5dca7903a8 Mon Sep 17 00:00:00 2001 From: Frank Richter Date: Sun, 2 Jan 2022 13:40:59 +0100 Subject: [PATCH 09/10] Expand comment on 'FLS early cleanup avoidance' in mi_process_init() --- src/init.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/init.c b/src/init.c index 47aa2b23..19519151 100644 --- a/src/init.c +++ b/src/init.c @@ -494,8 +494,11 @@ void mi_process_init(void) mi_attr_noexcept { _mi_verbose_message("secure level: %d\n", MI_SECURE); mi_thread_init(); #if defined(_WIN32) && !defined(MI_SHARED_LIB) - // When building as a static lib FLS cleanup happens to early for the main thread. - // Make it a no-op and perform it explicitly later. + /* When building as a static lib the FLS cleanup happens to early for the main thread. + * To avoid that set the FLS value for the main thread to NULL; the eventual + * mi_fls_done() execution won't call _mi_thread_done(). + * The latter function is later called explicitly from mi_process_done(). + * See GitHub issue #508 for more background and explanation. */ FlsSetValue(mi_fls_key, NULL); #endif mi_stats_reset(); // only call stat reset *after* thread init (or the heap tld == NULL) @@ -527,7 +530,7 @@ static void mi_process_done(void) { process_done = true; #if defined(_WIN32) && !defined(MI_SHARED_LIB) - // Explicitly clean up main thread + // Explicitly clean up main thread. See comment in mi_process_init() for reason _mi_thread_done(_mi_heap_default); FlsSetValue(mi_fls_key, NULL); // don't call main-thread callback FlsFree(mi_fls_key); // call thread-done on all threads to prevent dangling callback pointer if statically linked with a DLL; Issue #208 From 17762a7eb124a6dd43644166db985a3d2263c30b Mon Sep 17 00:00:00 2001 From: Frank Richter Date: Sun, 2 Jan 2022 13:41:16 +0100 Subject: [PATCH 10/10] Remove a redundant FlsSetValue() --- src/init.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/init.c b/src/init.c index 19519151..ee347081 100644 --- a/src/init.c +++ b/src/init.c @@ -532,7 +532,6 @@ static void mi_process_done(void) { #if defined(_WIN32) && !defined(MI_SHARED_LIB) // Explicitly clean up main thread. See comment in mi_process_init() for reason _mi_thread_done(_mi_heap_default); - FlsSetValue(mi_fls_key, NULL); // don't call main-thread callback FlsFree(mi_fls_key); // call thread-done on all threads to prevent dangling callback pointer if statically linked with a DLL; Issue #208 #endif