#include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #include static void msleep(unsigned long msecs) { Sleep(msecs); } #else #include static void msleep(unsigned long msecs) { usleep(msecs * 1000UL); } #endif static void theap_thread_free_large(); // issue #221 static void theap_no_delete(); // issue #202 static void theap_late_free(); // issue #204 static void padding_shrink(); // issue #209 static void various_tests(); static void test_mt_shutdown(); static void fail_aslr(); // issue #372 static void tsan_numa_test(); // issue #414 static void strdup_test(); // issue #445 static void theap_thread_free_huge(); static void test_std_string(); // issue #697 static void test_thread_local(); // issue #944 // static void test_mixed0(); // issue #942 static void test_mixed1(); // issue #942 static void test_stl_allocators(); static void test_join(); // issue #1177 static void test_thread_leak(void); // issue #1104 static void test_perf(void); // issue #1104 static void test_perf2(void); // issue #1104 static void test_perf3(void); // issue #1104 static void test_perf4(void); // issue #1104 static void test_perf5(void); // issue #1104 #if _WIN32 #include "main-override-dep.h" static void test_dep(); // issue #981: test overriding in another DLL #else static void test_dep() { }; #endif int main() { mi_stats_reset(); // ignore earlier allocations //various_tests(); //test_mixed1(); // test_dep(); // test_join(); // test_thread_leak(); // test_perf(); // test_perf2(); // test_perf3(); // test_perf4(); test_perf5(); //test_std_string(); //test_thread_local(); // theap_thread_free_huge(); /* theap_thread_free_large(); theap_no_delete(); theap_late_free(); padding_shrink(); tsan_numa_test(); */ /* strdup_test(); test_stl_allocators(); test_mt_shutdown(); */ //fail_aslr(); mi_stats_print(NULL); return 0; } static void* p = malloc(8); void free_p() { free(p); return; } class Test { private: int i; public: Test(int x) { i = x; } ~Test() { } }; static void various_tests() { atexit(free_p); void* p1 = malloc(78); void* p2 = mi_malloc_aligned(24, 16); free(p1); p1 = malloc(8); char* s = mi_strdup("hello\n"); mi_free(p2); p2 = malloc(16); p1 = realloc(p1, 32); free(p1); free(p2); mi_free(s); Test* t = new Test(42); delete t; t = new (std::nothrow) Test(42); delete t; auto tbuf = new unsigned char[sizeof(Test)]; t = new (tbuf) Test(42); t->~Test(); delete[] tbuf; #if _WIN32 const char* ptr = ::_Getdays(); // test _base overrid free((void*)ptr); #endif } class Static { private: void* p; public: Static() { p = malloc(64); return; } ~Static() { free(p); return; } }; static Static s = Static(); static bool test_stl_allocator1() { std::vector > vec; vec.push_back(1); vec.pop_back(); return vec.size() == 0; } struct some_struct { int i; int j; double z; }; #if _WIN32 static void test_dep() { TestAllocInDll t; std::string s = t.GetString(); std::cout << "test_dep GetString: " << s << "\n"; t.TestHeapAlloc(); } #endif static bool test_stl_allocator2() { std::vector > vec; vec.push_back(some_struct()); vec.pop_back(); return vec.size() == 0; } #if MI_HAS_HEAP_STL_ALLOCATOR static bool test_stl_allocator3() { std::vector > vec; vec.push_back(1); vec.pop_back(); return vec.size() == 0; } static bool test_stl_allocator4() { std::vector > vec; vec.push_back(some_struct()); vec.pop_back(); return vec.size() == 0; } static bool test_stl_allocator5() { std::vector > vec; vec.push_back(1); vec.pop_back(); return vec.size() == 0; } static bool test_stl_allocator6() { std::vector > vec; vec.push_back(some_struct()); vec.pop_back(); return vec.size() == 0; } #endif static void test_stl_allocators() { test_stl_allocator1(); test_stl_allocator2(); #if MI_HAS_HEAP_STL_ALLOCATOR test_stl_allocator3(); test_stl_allocator4(); test_stl_allocator5(); test_stl_allocator6(); #endif } #if 0 #include #include #include #include #include #include static void test_mixed0() { std::vector> numbers(1024 * 1024 * 100); std::vector threads(1); std::atomic index{}; auto start = std::chrono::system_clock::now(); for (auto& thread : threads) { thread = std::thread{[&index, &numbers]() { while (true) { auto i = index.fetch_add(1, std::memory_order_relaxed); if (i >= numbers.size()) return; numbers[i] = std::make_unique(i); } }}; } for (auto& thread : threads) thread.join(); auto end = std::chrono::system_clock::now(); auto duration = std::chrono::duration_cast(end - start); std::cout << "Running on " << threads.size() << " threads took " << duration << std::endl; } #endif void asd() { void* p = malloc(128); free(p); } static void test_mixed1() { std::thread thread(asd); thread.join(); } #if 0 // issue #691 static char* cptr; static void* thread1_allocate() { cptr = mi_calloc_tp(char,22085632); return NULL; } static void* thread2_free() { assert(cptr); mi_free(cptr); cptr = NULL; return NULL; } static void test_large_migrate(void) { auto t1 = std::thread(thread1_allocate); t1.join(); auto t2 = std::thread(thread2_free); t2.join(); /* pthread_t thread1, thread2; pthread_create(&thread1, NULL, &thread1_allocate, NULL); pthread_join(thread1, NULL); pthread_create(&thread2, NULL, &thread2_free, NULL); pthread_join(thread2, NULL); */ return; } #endif // issue 445 static void strdup_test() { #ifdef _MSC_VER char* s = _strdup("hello\n"); char* buf = NULL; size_t len; _dupenv_s(&buf, &len, "MIMALLOC_VERBOSE"); mi_free(buf); mi_free(s); #endif } // Issue #202 static void heap_no_delete_worker() { mi_heap_t* heap = mi_heap_new(); void* q = mi_heap_malloc(heap, 1024); (void)(q); // mi_heap_delete(heap); // uncomment to prevent assertion } static void heap_no_delete() { auto t1 = std::thread(heap_no_delete_worker); t1.join(); } // Issue #697 static void test_std_string() { std::string path = "/Users/xxxx/Library/Developer/Xcode/DerivedData/xxxxxxxxxx/Build/Intermediates.noindex/xxxxxxxxxxx/arm64/XX_lto.o/0.arm64.lto.o"; std::string path1 = "/Users/xxxx/Library/Developer/Xcode/DerivedData/xxxxxxxxxx/Build/Intermediates.noindex/xxxxxxxxxxx/arm64/XX_lto.o/1.arm64.lto.o"; std::cout << path + "\n>>> " + path1 + "\n>>> " << std::endl; } // Issue #204 static volatile void* global_p; static void t1main() { mi_heap_t* heap = mi_heap_new(); global_p = mi_heap_malloc(heap, 1024); mi_heap_delete(heap); } static void theap_late_free() { auto t1 = std::thread(t1main); msleep(2000); assert(global_p); mi_free((void*)global_p); t1.join(); } // issue #209 static void* shared_p; static void alloc0(/* void* arg */) { shared_p = mi_malloc(8); } static void padding_shrink(void) { auto t1 = std::thread(alloc0); t1.join(); mi_free(shared_p); } // Issue #221 static void theap_thread_free_large_worker() { mi_free(shared_p); } static void theap_thread_free_large() { for (int i = 0; i < 100; i++) { shared_p = mi_malloc_aligned(2*1024*1024 + 1, 8); auto t1 = std::thread(theap_thread_free_large_worker); t1.join(); } } static void theap_thread_free_huge_worker() { mi_free(shared_p); } static void theap_thread_free_huge() { for (int i = 0; i < 10; i++) { shared_p = mi_malloc(1024 * 1024 * 1024); auto t1 = std::thread(theap_thread_free_huge_worker); t1.join(); } } static std::atomic xgsum; static void local_alloc() { long sum = 0; for(int i = 0; i < 1000000; i++) { const int n = 1 + std::rand() % 1000; uint8_t* p = (uint8_t*)calloc(n, 1); p[0] = 1; sum += p[std::rand() % n]; if ((std::rand() % 100) > 24) { free(p); } } xgsum += sum; } static void test_thread_leak() { std::vector threads; for (int i=1; i<=100; ++i) { threads.emplace_back(std::thread(&local_alloc)); } for (auto& th : threads) { th.join(); } } static void test_mt_shutdown() { const int threads = 5; std::vector< std::future< std::vector< char* > > > ts; auto fn = [&]() { std::vector< char* > ps; ps.reserve(1000); for (int i = 0; i < 1000; i++) ps.emplace_back(new char[1]); return ps; }; for (int i = 0; i < threads; i++) ts.emplace_back(std::async(std::launch::async, fn)); for (auto& f : ts) for (auto& p : f.get()) delete[] p; std::cout << "done" << std::endl; } // issue #372 static void fail_aslr() { size_t sz = (size_t)(4ULL << 40); // 4TiB void* p = malloc(sz); printf("pointer p: %p: area up to %p\n", p, (uint8_t*)p + sz); *(int*)0x5FFFFFFF000 = 0; // should segfault } // issues #414 static void dummy_worker() { void* p = mi_malloc(0); mi_free(p); } static void tsan_numa_test() { auto t1 = std::thread(dummy_worker); dummy_worker(); t1.join(); } class MTest { char *data; public: MTest() { data = (char*)malloc(1024); } ~MTest() { free(data); }; }; thread_local MTest tlVariable; void threadFun( int i ) { printf( "Thread %d\n", i ); std::this_thread::sleep_for( std::chrono::milliseconds(100) ); } void test_thread_local() { for( int i=1; i < 100; ++i ) { std::thread t( threadFun, i ); t.join(); mi_stats_print(NULL); } return; } // issue #1177 thread_local void* s_ptr = mi_malloc(1); void test_join() { std::thread thread([]() { mi_free(s_ptr); }); thread.join(); mi_free(s_ptr); } static std::atomic gsum; const int LEN[] = { 1000, 5000, 10000, 50000 }; // adapted from example in // https://github.com/microsoft/mimalloc/issues/1104 static void test_perf_local_alloc() { // thread-local random number generator std::minstd_rand rng(std::random_device{}()); long sum = 0; for (int i = 0; i < 1000000; i++) { int len = LEN[rng() % 4]; int* p = (int*)mi_zalloc_aligned(len * sizeof(int), alignof(int)); p[0] = 1; sum += p[rng() % len]; free(p); } std::cout << "."; gsum += sum; } static void test_perf_run() { std::vector threads; for (int i = 0; i < 24; ++i) { threads.emplace_back(std::thread(&test_perf_local_alloc)); } for (auto& th : threads) { th.join(); } std::cout << "\n"; } void test_perf(void) { test_perf_run(); std::cout << "gsum: " << gsum.load() << "\n"; } static int sum2; static void escape(uint8_t* p, size_t n) { if (n==0) return; p[std::rand() % n] = 42; sum2 += p[std::rand() % n]; } void test_perf2(void) { for (size_t i = 0; i < 100000000; i++) { const size_t n = 1000; uint8_t* p = (uint8_t*)calloc(1, n); escape(p,n); free(p); } } void test_perf3(void) { for (size_t i = 0; i < 5; i++) { const size_t n = (size_t)1*1024*1024*1024; uint8_t* p = (uint8_t*)calloc(1, n); escape(p, n); free(p); } } static void local_alloc4() { for (int i = 0; i < 1000000; i++) { const size_t n = i%1000; uint8_t* p = (uint8_t*)calloc(1,n); escape(p,n); if (i % 4 > 0) { free(p); } } } static void test_perf4(void) { std::vector threads; for (int i = 1; i <= 100; ++i) { threads.emplace_back(std::thread(&local_alloc4)); } for (auto& th : threads) { th.join(); } } void escape5(uint8_t* p, size_t n) { if (n==0) return; for (size_t i = 0; i < n; i++) { p[i] = (uint8_t)(i & 0xFF); } p[rand() % n] = (uint8_t)(n&0xFF); // asm volatile("" : : "g"(p) : "memory"); } static long gsum5; static void local_alloc5() { long sum = 0; for (int i = 0; i < 500000; i++) { const size_t n = i % 1000; uint8_t* p = (uint8_t*)mi_malloc(n); escape5(p, n); if (i % 4 > 0) { if (n>0) { sum += p[n-1]; } mi_free(p); } } gsum5 += sum; } static void test_perf5(void) { std::vector threads; for (int i = 1; i <= 100; ++i) { threads.emplace_back(std::thread(&local_alloc5)); } for (auto& th : threads) { th.join(); } printf("gsum5: %li\n", gsum5); }