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 
18 #define __TBB_NO_IMPLICIT_LINKAGE 1
19 
20 #if _USRDLL
21 #include "common/utils_assert.h"
22 #include <stdlib.h> // for NULL
23 
24 const char *globalCallMsg = "A TBB allocator function call is resolved into wrong implementation.";
25 
26 #if _WIN32||_WIN64
27 // must be defined in DLL for linker to not drop the dependency on the DLL.
28 extern "C" {
29     extern __declspec(dllexport) void *scalable_malloc(size_t);
30     extern __declspec(dllexport) void scalable_free (void *);
31     extern __declspec(dllexport) void safer_scalable_free (void *, void (*)(void*));
32     extern __declspec(dllexport) void *scalable_realloc(void *, size_t);
33     extern __declspec(dllexport) void *safer_scalable_realloc(void *, size_t, void *);
34     extern __declspec(dllexport) void *scalable_calloc(size_t, size_t);
35     extern __declspec(dllexport) int scalable_posix_memalign(void **, size_t, size_t);
36     extern __declspec(dllexport) void *scalable_aligned_malloc(size_t, size_t);
37     extern __declspec(dllexport) void *scalable_aligned_realloc(void *, size_t, size_t);
38     extern __declspec(dllexport) void *safer_scalable_aligned_realloc(void *, size_t, size_t, void *);
39     extern __declspec(dllexport) void scalable_aligned_free(void *);
40     extern __declspec(dllexport) size_t scalable_msize(void *);
41     extern __declspec(dllexport) size_t safer_scalable_msize (void *, size_t (*)(void*));
42     extern __declspec(dllexport) int anchor();
43 }
44 #endif
45 
46 extern "C" int anchor() {
47     return 42;
48 }
49 
50 // Those functions must not be called instead of presented in dynamic library.
51 extern "C" void *scalable_malloc(size_t)
52 {
53     ASSERT(0, globalCallMsg);
54     return NULL;
55 }
56 extern "C" void scalable_free (void *)
57 {
58     ASSERT(0, globalCallMsg);
59 }
60 extern "C" void safer_scalable_free (void *, void (*)(void*))
61 {
62     ASSERT(0, globalCallMsg);
63 }
64 extern "C" void *scalable_realloc(void *, size_t)
65 {
66     ASSERT(0, globalCallMsg);
67     return NULL;
68 }
69 extern "C" void *safer_scalable_realloc(void *, size_t, void *)
70 {
71     ASSERT(0, globalCallMsg);
72     return NULL;
73 }
74 extern "C" void *scalable_calloc(size_t, size_t)
75 {
76     ASSERT(0, globalCallMsg);
77     return NULL;
78 }
79 extern "C" int scalable_posix_memalign(void **, size_t, size_t)
80 {
81     ASSERT(0, globalCallMsg);
82     return 0;
83 }
84 extern "C" void *scalable_aligned_malloc(size_t, size_t)
85 {
86     ASSERT(0, globalCallMsg);
87     return NULL;
88 }
89 extern "C" void *scalable_aligned_realloc(void *, size_t, size_t)
90 {
91     ASSERT(0, globalCallMsg);
92     return NULL;
93 }
94 extern "C" void *safer_scalable_aligned_realloc(void *, size_t, size_t, void *)
95 {
96     ASSERT(0, globalCallMsg);
97     return NULL;
98 }
99 extern "C" void scalable_aligned_free(void *)
100 {
101     ASSERT(0, globalCallMsg);
102 }
103 extern "C" size_t scalable_msize(void *)
104 {
105     ASSERT(0, globalCallMsg);
106     return 0;
107 }
108 extern "C" size_t safer_scalable_msize (void *, size_t (*)(void*))
109 {
110     ASSERT(0, globalCallMsg);
111     return 0;
112 }
113 
114 int main() {}
115 
116 #else  // _USRDLL
117 
118 #include "common/config.h"
119 // harness_defs.h must be included before tbb_stddef.h to overcome exception-dependent
120 // system headers that come from tbb_stddef.h
121 #if __TBB_WIN8UI_SUPPORT || __TBB_MIC_OFFLOAD || (__GNUC__ && __GNUC__ < 10 && __TBB_USE_SANITIZERS) || __TBB_SOURCE_DIRECTLY_INCLUDED
122 // The test does not work if dynamic load is unavailable.
123 // For MIC offload, it fails because liboffload brings libiomp which observes and uses the fake scalable_* calls.
124 // For sanitizers, it fails because RUNPATH is lost: https://github.com/google/sanitizers/issues/1219
125 #else
126 #include "common/test.h"
127 #include "common/memory_usage.h"
128 #include "common/utils_dynamic_libs.h"
129 #include "common/utils_assert.h"
130 #include "common/utils_report.h"
131 #include <cstring> // memset
132 
133 extern "C" {
134 #if _WIN32||_WIN64
135     extern __declspec(dllimport)
136 #endif
137     void *scalable_malloc(size_t);
138 
139 #if _WIN32||_WIN64
140     extern __declspec(dllimport)
141 #endif
142     int anchor();
143 }
144 
145 struct Run {
146     void operator()( std::size_t /*id*/ ) const {
147 
148         void* (*malloc_ptr)(std::size_t);
149         void (*free_ptr)(void*);
150 
151         void* (*aligned_malloc_ptr)(size_t size, size_t alignment);
152         void  (*aligned_free_ptr)(void*);
153 
154         const char* actual_name;
155         utils::LIBRARY_HANDLE lib = utils::OpenLibrary(actual_name = MALLOCLIB_NAME1);
156         if (!lib) lib = utils::OpenLibrary(actual_name = MALLOCLIB_NAME2);
157         if (!lib) {
158             REPORT("Can't load " MALLOCLIB_NAME1 " or " MALLOCLIB_NAME2 "\n");
159             exit(1);
160         }
161         utils::GetAddress(lib, "scalable_malloc", malloc_ptr);
162         utils::GetAddress(lib, "scalable_free", free_ptr);
163         utils::GetAddress(lib, "scalable_aligned_malloc", aligned_malloc_ptr);
164         utils::GetAddress(lib, "scalable_aligned_free", aligned_free_ptr);
165 
166         for (size_t sz = 1024; sz <= 10*1024 ; sz*=10) {
167             void *p1 = aligned_malloc_ptr(sz, 16);
168             std::memset(p1, 0, sz);
169             aligned_free_ptr(p1);
170         }
171 
172         void *p = malloc_ptr(100);
173         std::memset(p, 1, 100);
174         free_ptr(p);
175 
176         utils::CloseLibrary(lib);
177 #if _WIN32 || _WIN64
178         ASSERT(GetModuleHandle(actual_name),
179                "allocator library must not be unloaded");
180 #else
181         ASSERT(dlsym(RTLD_DEFAULT, "scalable_malloc"),
182                "allocator library must not be unloaded");
183 #endif
184     }
185 };
186 
187 //! \brief \ref error_guessing
188 TEST_CASE("test unload lib") {
189     CHECK(anchor() == 42);
190 
191     // warm-up run
192     utils::NativeParallelFor( 1, Run() );
193 
194     // It seems Thread Sanitizer remembers some history information about destroyed threads,
195     // so memory consumption cannot be stabilized
196     std::ptrdiff_t memory_leak = 0;
197     {
198         /* 1st call to GetMemoryUsage() allocate some memory,
199            but it seems memory consumption stabilized after this.
200         */
201         utils::GetMemoryUsage();
202         std::size_t memory_in_use = utils::GetMemoryUsage();
203         std::size_t memory_check = utils::GetMemoryUsage();
204         REQUIRE_MESSAGE(memory_in_use == memory_check,
205             "Memory consumption should not increase after 1st GetMemoryUsage() call");
206     }
207 
208     {
209         // expect that memory consumption stabilized after several runs
210         for (;;) {
211             std::size_t memory_in_use = utils::GetMemoryUsage();
212             for (int j=0; j<10; j++)
213                 utils::NativeParallelFor( 1, Run() );
214             memory_leak = utils::GetMemoryUsage() - memory_in_use;
215             if (memory_leak == 0)
216                 return;
217         }
218     }
219 }
220 
221 #endif /* Unsupported configurations */
222 
223 #endif // _USRDLL
224