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