1 /* 2 Copyright (c) 2005-2021 Intel Corporation 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 /* Regression test against a bug in TBB allocator manifested when 18 dynamic library calls atexit() or registers dtors of static objects. 19 If the allocator is not initialized yet, we can get deadlock, 20 because allocator library has static object dtors as well, they 21 registered during allocator initialization, and atexit() is protected 22 by non-recursive mutex in some versions of GLIBC. 23 */ 24 25 #define __TBB_NO_IMPLICIT_LINKAGE 1 26 27 #include "common/allocator_overload.h" 28 #include "common/utils_assert.h" 29 #include <stdlib.h> 30 31 // __TBB_malloc_safer_msize() returns 0 for unknown objects, 32 // thus we can detect ownership 33 #if _USRDLL 34 #if _WIN32||_WIN64 35 extern __declspec(dllexport) 36 #endif 37 bool dll_isMallocOverloaded() 38 #else 39 bool exe_isMallocOverloaded() 40 #endif 41 { 42 const size_t reqSz = 8; 43 void *o = malloc(reqSz); 44 bool ret = __TBB_malloc_safer_msize(o, NULL) >= reqSz; 45 free(o); 46 return ret; 47 } 48 49 #if _USRDLL 50 #include "common/utils_report.h" 51 52 #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED 53 54 #include <dlfcn.h> 55 #if __APPLE__ 56 #include <malloc/malloc.h> 57 #define malloc_usable_size(p) malloc_size(p) 58 #else 59 #include <malloc.h> 60 #endif 61 #include <signal.h> 62 63 #if __linux__ && !__ANDROID__ 64 extern "C" { 65 void __libc_free(void *ptr); 66 void *__libc_realloc(void *ptr, size_t size); 67 68 // check that such kind of free/realloc overload works correctly 69 void free(void *ptr) 70 { 71 __libc_free(ptr); 72 } 73 74 void *realloc(void *ptr, size_t size) 75 { 76 return __libc_realloc(ptr, size); 77 } 78 } // extern "C" 79 #endif // __linux__ && !__ANDROID__ 80 81 #endif // MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED 82 83 // Even when the test is skipped, dll source must not be empty to generate .lib to link with. 84 85 #ifndef _PGO_INSTRUMENT 86 void dummyFunction() {} 87 88 // TODO: enable the check under Android 89 #if (MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED) && !__ANDROID__ 90 typedef void *(malloc_type)(size_t); 91 92 static void SigSegv(int) 93 { 94 REPORT("Known issue: SIGSEGV during work with memory allocated by replaced allocator.\n" 95 "skip\n"); 96 exit(0); 97 } 98 99 // TODO: Using of SIGSEGV can be eliminated via parsing /proc/self/maps 100 // and series of system malloc calls. 101 void TestReplacedAllocFunc() 102 { 103 struct sigaction sa, sa_default; 104 malloc_type *orig_malloc = (malloc_type*)dlsym(RTLD_NEXT, "malloc"); 105 void *p = (*orig_malloc)(16); 106 107 // protect potentially unsafe actions 108 sigemptyset(&sa.sa_mask); 109 sa.sa_flags = 0; 110 sa.sa_handler = SigSegv; 111 if (sigaction(SIGSEGV, &sa, &sa_default)) 112 ASSERT(0, "sigaction failed"); 113 114 ASSERT(malloc_usable_size(p) >= 16, NULL); 115 free(p); 116 // no more unsafe actions, restore SIGSEGV 117 if (sigaction(SIGSEGV, &sa_default, NULL)) 118 ASSERT(0, "sigaction failed"); 119 } 120 #else 121 void TestReplacedAllocFunc() { } 122 #endif 123 124 class Foo { 125 public: 126 Foo() { 127 // add a lot of exit handlers to cause memory allocation 128 for (int i=0; i<1024; i++) 129 atexit(dummyFunction); 130 TestReplacedAllocFunc(); 131 } 132 }; 133 134 static Foo f; 135 #endif 136 137 int main() {} 138 139 #else // _USRDLL 140 #include "common/test.h" 141 142 #if _WIN32||_WIN64 143 #include "tbb/tbbmalloc_proxy.h" 144 145 extern __declspec(dllimport) 146 #endif 147 bool dll_isMallocOverloaded(); 148 149 #ifdef _PGO_INSTRUMENT 150 //! \brief \ref error_guessing 151 TEST_CASE("Known issue: test_malloc_atexit hangs if compiled with -prof-genx\n" * doctest::skip(true)) {} 152 #else 153 // Check common/allocator_overload.h for skip cases 154 #if !HARNESS_SKIP_TEST 155 //! \brief \ref error_guessing 156 TEST_CASE("test malloc atexit") { 157 REQUIRE_MESSAGE( dll_isMallocOverloaded(), "malloc was not replaced" ); 158 REQUIRE_MESSAGE( exe_isMallocOverloaded(), "malloc was not replaced" ); 159 } 160 #endif // HARNESS_SKIP_TEST 161 162 #endif // _PGO_INSTRUMENT 163 164 #endif // _USRDLL 165