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