1*51c0b2f7Stbbdev /*
2*51c0b2f7Stbbdev     Copyright (c) 2005-2020 Intel Corporation
3*51c0b2f7Stbbdev 
4*51c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
5*51c0b2f7Stbbdev     you may not use this file except in compliance with the License.
6*51c0b2f7Stbbdev     You may obtain a copy of the License at
7*51c0b2f7Stbbdev 
8*51c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
9*51c0b2f7Stbbdev 
10*51c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
11*51c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
12*51c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*51c0b2f7Stbbdev     See the License for the specific language governing permissions and
14*51c0b2f7Stbbdev     limitations under the License.
15*51c0b2f7Stbbdev */
16*51c0b2f7Stbbdev 
17*51c0b2f7Stbbdev //! \file test_malloc_overload.cpp
18*51c0b2f7Stbbdev //! \brief Test for [memory_allocation] functionality
19*51c0b2f7Stbbdev 
20*51c0b2f7Stbbdev #define __TBB_NO_IMPLICIT_LINKAGE 1
21*51c0b2f7Stbbdev 
22*51c0b2f7Stbbdev #if (_WIN32 || _WIN64)
23*51c0b2f7Stbbdev // As the test is intentionally build with /EHs-, suppress multiple VS2005's
24*51c0b2f7Stbbdev // warnings like C4530: C++ exception handler used, but unwind semantics are not enabled
25*51c0b2f7Stbbdev #if defined(_MSC_VER) && !__INTEL_COMPILER
26*51c0b2f7Stbbdev /* ICC 10.1 and 11.0 generates code that uses std::_Raise_handler,
27*51c0b2f7Stbbdev    but it's only defined in libcpmt(d), which the test doesn't linked with.
28*51c0b2f7Stbbdev  */
29*51c0b2f7Stbbdev #undef  _HAS_EXCEPTIONS
30*51c0b2f7Stbbdev #define _HAS_EXCEPTIONS _CPPUNWIND
31*51c0b2f7Stbbdev #endif
32*51c0b2f7Stbbdev // to use strdup w/o warnings
33*51c0b2f7Stbbdev #define _CRT_NONSTDC_NO_DEPRECATE 1
34*51c0b2f7Stbbdev #endif // _WIN32 || _WIN64
35*51c0b2f7Stbbdev 
36*51c0b2f7Stbbdev #define _ISOC11_SOURCE 1 // to get C11 declarations for GLIBC
37*51c0b2f7Stbbdev 
38*51c0b2f7Stbbdev #include "common/allocator_overload.h"
39*51c0b2f7Stbbdev 
40*51c0b2f7Stbbdev #if MALLOC_WINDOWS_OVERLOAD_ENABLED
41*51c0b2f7Stbbdev #include "tbb/tbbmalloc_proxy.h"
42*51c0b2f7Stbbdev #endif
43*51c0b2f7Stbbdev 
44*51c0b2f7Stbbdev #include "common/test.h"
45*51c0b2f7Stbbdev 
46*51c0b2f7Stbbdev #if !HARNESS_SKIP_TEST
47*51c0b2f7Stbbdev 
48*51c0b2f7Stbbdev #if __ANDROID__
49*51c0b2f7Stbbdev   #include <android/api-level.h> // for __ANDROID_API__
50*51c0b2f7Stbbdev #endif
51*51c0b2f7Stbbdev 
52*51c0b2f7Stbbdev #define __TBB_POSIX_MEMALIGN_PRESENT (__linux__ && !__ANDROID__) || __APPLE__
53*51c0b2f7Stbbdev #define __TBB_PVALLOC_PRESENT __linux__ && !__ANDROID__
54*51c0b2f7Stbbdev #if __GLIBC__
55*51c0b2f7Stbbdev   // aligned_alloc available since GLIBC 2.16
56*51c0b2f7Stbbdev   #define __TBB_ALIGNED_ALLOC_PRESENT __GLIBC_PREREQ(2, 16)
57*51c0b2f7Stbbdev #endif // __GLIBC__
58*51c0b2f7Stbbdev  // later Android doesn't have valloc or dlmalloc_usable_size
59*51c0b2f7Stbbdev #define __TBB_VALLOC_PRESENT (__linux__ && __ANDROID_API__<21) || __APPLE__
60*51c0b2f7Stbbdev #define __TBB_DLMALLOC_USABLE_SIZE_PRESENT  __ANDROID__ && __ANDROID_API__<21
61*51c0b2f7Stbbdev 
62*51c0b2f7Stbbdev #include "common/utils.h"
63*51c0b2f7Stbbdev #include "common/utils_report.h"
64*51c0b2f7Stbbdev #include "common/utils_assert.h"
65*51c0b2f7Stbbdev #include "common/utils_env.h"
66*51c0b2f7Stbbdev 
67*51c0b2f7Stbbdev #include <stdlib.h>
68*51c0b2f7Stbbdev #include <string.h>
69*51c0b2f7Stbbdev #if !__APPLE__
70*51c0b2f7Stbbdev #include <malloc.h>
71*51c0b2f7Stbbdev #endif
72*51c0b2f7Stbbdev #include <stdio.h>
73*51c0b2f7Stbbdev #include <new>
74*51c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED
75*51c0b2f7Stbbdev #include <unistd.h> // for sysconf
76*51c0b2f7Stbbdev #include <dlfcn.h>
77*51c0b2f7Stbbdev #endif
78*51c0b2f7Stbbdev 
79*51c0b2f7Stbbdev #if __linux__
80*51c0b2f7Stbbdev #include <stdint.h> // for uintptr_t
81*51c0b2f7Stbbdev 
82*51c0b2f7Stbbdev extern "C" {
83*51c0b2f7Stbbdev void *__libc_malloc(size_t size);
84*51c0b2f7Stbbdev void *__libc_realloc(void *ptr, size_t size);
85*51c0b2f7Stbbdev void *__libc_calloc(size_t num, size_t size);
86*51c0b2f7Stbbdev void __libc_free(void *ptr);
87*51c0b2f7Stbbdev void *__libc_memalign(size_t alignment, size_t size);
88*51c0b2f7Stbbdev void *__libc_pvalloc(size_t size);
89*51c0b2f7Stbbdev void *__libc_valloc(size_t size);
90*51c0b2f7Stbbdev #if __TBB_DLMALLOC_USABLE_SIZE_PRESENT
91*51c0b2f7Stbbdev #define malloc_usable_size(p) dlmalloc_usable_size(p)
92*51c0b2f7Stbbdev size_t dlmalloc_usable_size(const void *ptr);
93*51c0b2f7Stbbdev #endif
94*51c0b2f7Stbbdev }
95*51c0b2f7Stbbdev 
96*51c0b2f7Stbbdev #elif __APPLE__
97*51c0b2f7Stbbdev 
98*51c0b2f7Stbbdev #include <malloc/malloc.h>
99*51c0b2f7Stbbdev #define malloc_usable_size(p) malloc_size(p)
100*51c0b2f7Stbbdev 
101*51c0b2f7Stbbdev #elif _WIN32
102*51c0b2f7Stbbdev #include <stddef.h>
103*51c0b2f7Stbbdev #if __MINGW32__
104*51c0b2f7Stbbdev #include <unistd.h>
105*51c0b2f7Stbbdev #else
106*51c0b2f7Stbbdev typedef unsigned __int16 uint16_t;
107*51c0b2f7Stbbdev typedef unsigned __int32 uint32_t;
108*51c0b2f7Stbbdev typedef unsigned __int64 uint64_t;
109*51c0b2f7Stbbdev #endif
110*51c0b2f7Stbbdev 
111*51c0b2f7Stbbdev #endif /* OS selection */
112*51c0b2f7Stbbdev 
113*51c0b2f7Stbbdev #if _WIN32
114*51c0b2f7Stbbdev // On Windows, the trick with string "dependency on msvcpXX.dll" is necessary to create
115*51c0b2f7Stbbdev // dependency on msvcpXX.dll, for sake of a regression test.
116*51c0b2f7Stbbdev // On Linux, C++ RTL headers are undesirable because of breaking strict ANSI mode.
117*51c0b2f7Stbbdev #if defined(_MSC_VER) && _MSC_VER >= 1300 && _MSC_VER <= 1310 && !defined(__INTEL_COMPILER)
118*51c0b2f7Stbbdev /* Fixing compilation error reported by VS2003 for exception class
119*51c0b2f7Stbbdev    when _HAS_EXCEPTIONS is 0:
120*51c0b2f7Stbbdev    bad_cast that inherited from exception is not in std namespace.
121*51c0b2f7Stbbdev */
122*51c0b2f7Stbbdev using namespace std;
123*51c0b2f7Stbbdev #endif
124*51c0b2f7Stbbdev #include <string>
125*51c0b2f7Stbbdev #include <set>
126*51c0b2f7Stbbdev #include <sstream>
127*51c0b2f7Stbbdev #endif
128*51c0b2f7Stbbdev 
129*51c0b2f7Stbbdev #include "tbb/detail/_utils.h"  // tbb::detail::is_aligned
130*51c0b2f7Stbbdev #include "src/tbbmalloc/shared_utils.h"  // alignDown, alignUp, estimatedCacheLineSize
131*51c0b2f7Stbbdev 
132*51c0b2f7Stbbdev /* start of code replicated from src/tbbmalloc */
133*51c0b2f7Stbbdev 
134*51c0b2f7Stbbdev class BackRefIdx { // composite index to backreference array
135*51c0b2f7Stbbdev private:
136*51c0b2f7Stbbdev     uint16_t master;      // index in BackRefMaster
137*51c0b2f7Stbbdev     uint16_t largeObj:1;  // is this object "large"?
138*51c0b2f7Stbbdev     uint16_t offset  :15; // offset from beginning of BackRefBlock
139*51c0b2f7Stbbdev public:
140*51c0b2f7Stbbdev     BackRefIdx() : master((uint16_t)-1) {}
141*51c0b2f7Stbbdev     bool isInvalid() { return master == (uint16_t)-1; }
142*51c0b2f7Stbbdev     bool isLargeObject() const { return largeObj; }
143*51c0b2f7Stbbdev     uint16_t getMaster() const { return master; }
144*51c0b2f7Stbbdev     uint16_t getOffset() const { return offset; }
145*51c0b2f7Stbbdev 
146*51c0b2f7Stbbdev     // only newBackRef can modify BackRefIdx
147*51c0b2f7Stbbdev     static BackRefIdx newBackRef(bool largeObj);
148*51c0b2f7Stbbdev };
149*51c0b2f7Stbbdev 
150*51c0b2f7Stbbdev class MemoryPool;
151*51c0b2f7Stbbdev class ExtMemoryPool;
152*51c0b2f7Stbbdev 
153*51c0b2f7Stbbdev struct BlockI {
154*51c0b2f7Stbbdev     intptr_t     blockState[2];
155*51c0b2f7Stbbdev };
156*51c0b2f7Stbbdev 
157*51c0b2f7Stbbdev struct LargeMemoryBlock : public BlockI {
158*51c0b2f7Stbbdev     MemoryPool       *pool;          // owner pool
159*51c0b2f7Stbbdev     LargeMemoryBlock *next,          // ptrs in list of cached blocks
160*51c0b2f7Stbbdev                      *prev,
161*51c0b2f7Stbbdev                      *gPrev,         // in pool's global list
162*51c0b2f7Stbbdev                      *gNext;
163*51c0b2f7Stbbdev     uintptr_t         age;           // age of block while in cache
164*51c0b2f7Stbbdev     size_t            objectSize;    // the size requested by a client
165*51c0b2f7Stbbdev     size_t            unalignedSize; // the size requested from getMemory
166*51c0b2f7Stbbdev     bool              fromMapMemory;
167*51c0b2f7Stbbdev     BackRefIdx        backRefIdx;    // cached here, used copy is in LargeObjectHdr
168*51c0b2f7Stbbdev     void registerInPool(ExtMemoryPool *extMemPool);
169*51c0b2f7Stbbdev     void unregisterFromPool(ExtMemoryPool *extMemPool);
170*51c0b2f7Stbbdev };
171*51c0b2f7Stbbdev 
172*51c0b2f7Stbbdev struct LargeObjectHdr {
173*51c0b2f7Stbbdev     LargeMemoryBlock *memoryBlock;
174*51c0b2f7Stbbdev     /* Have to duplicate it here from CachedObjectHdr,
175*51c0b2f7Stbbdev        as backreference must be checked without further pointer dereference.
176*51c0b2f7Stbbdev        Points to LargeObjectHdr. */
177*51c0b2f7Stbbdev     BackRefIdx       backRefIdx;
178*51c0b2f7Stbbdev };
179*51c0b2f7Stbbdev 
180*51c0b2f7Stbbdev /*
181*51c0b2f7Stbbdev  * Objects of size minLargeObjectSize and larger are considered large objects.
182*51c0b2f7Stbbdev  */
183*51c0b2f7Stbbdev const uintptr_t blockSize = 16*1024;
184*51c0b2f7Stbbdev const uint32_t fittingAlignment = rml::internal::estimatedCacheLineSize;
185*51c0b2f7Stbbdev #define SET_FITTING_SIZE(N) ( (blockSize-2*rml::internal::estimatedCacheLineSize)/N ) & ~(fittingAlignment-1)
186*51c0b2f7Stbbdev const uint32_t fittingSize5 = SET_FITTING_SIZE(2); // 8128/8064
187*51c0b2f7Stbbdev #undef SET_FITTING_SIZE
188*51c0b2f7Stbbdev const uint32_t minLargeObjectSize = fittingSize5 + 1;
189*51c0b2f7Stbbdev 
190*51c0b2f7Stbbdev /* end of code replicated from src/tbbmalloc */
191*51c0b2f7Stbbdev 
192*51c0b2f7Stbbdev static void scalableMallocCheckSize(void *object, size_t size)
193*51c0b2f7Stbbdev {
194*51c0b2f7Stbbdev #if __clang__
195*51c0b2f7Stbbdev     // This prevents Clang from throwing out the calls to new & delete in CheckNewDeleteOverload().
196*51c0b2f7Stbbdev     static void *v = object;
197*51c0b2f7Stbbdev     utils::suppress_unused_warning(v);
198*51c0b2f7Stbbdev #endif
199*51c0b2f7Stbbdev     REQUIRE(object);
200*51c0b2f7Stbbdev     if (size >= minLargeObjectSize) {
201*51c0b2f7Stbbdev         LargeMemoryBlock *lmb = ((LargeObjectHdr*)object-1)->memoryBlock;
202*51c0b2f7Stbbdev         REQUIRE((uintptr_t(lmb)<uintptr_t(((LargeObjectHdr*)object-1)) && lmb->objectSize >= size));
203*51c0b2f7Stbbdev     }
204*51c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED
205*51c0b2f7Stbbdev     REQUIRE(malloc_usable_size(object) >= size);
206*51c0b2f7Stbbdev #elif MALLOC_WINDOWS_OVERLOAD_ENABLED
207*51c0b2f7Stbbdev     // Check that _msize works correctly
208*51c0b2f7Stbbdev     REQUIRE(_msize(object) >= size);
209*51c0b2f7Stbbdev     REQUIRE((size < 8 || _aligned_msize(object,8,0) >= size));
210*51c0b2f7Stbbdev #endif
211*51c0b2f7Stbbdev }
212*51c0b2f7Stbbdev 
213*51c0b2f7Stbbdev void CheckStdFuncOverload(void *(*malloc_p)(size_t), void *(*calloc_p)(size_t, size_t),
214*51c0b2f7Stbbdev                           void *(*realloc_p)(void *, size_t), void (*free_p)(void *))
215*51c0b2f7Stbbdev {
216*51c0b2f7Stbbdev     void *ptr = malloc_p(minLargeObjectSize);
217*51c0b2f7Stbbdev     scalableMallocCheckSize(ptr, minLargeObjectSize);
218*51c0b2f7Stbbdev     free(ptr);
219*51c0b2f7Stbbdev 
220*51c0b2f7Stbbdev     ptr = calloc_p(minLargeObjectSize, 2);
221*51c0b2f7Stbbdev     scalableMallocCheckSize(ptr, 2*minLargeObjectSize);
222*51c0b2f7Stbbdev     void *ptr1 = realloc_p(ptr, 10*minLargeObjectSize);
223*51c0b2f7Stbbdev     scalableMallocCheckSize(ptr1, 10*minLargeObjectSize);
224*51c0b2f7Stbbdev     free_p(ptr1);
225*51c0b2f7Stbbdev }
226*51c0b2f7Stbbdev 
227*51c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED
228*51c0b2f7Stbbdev 
229*51c0b2f7Stbbdev void CheckMemalignFuncOverload(void *(*memalign_p)(size_t, size_t),
230*51c0b2f7Stbbdev                                void (*free_p)(void*))
231*51c0b2f7Stbbdev {
232*51c0b2f7Stbbdev     void *ptr = memalign_p(128, 4*minLargeObjectSize);
233*51c0b2f7Stbbdev     scalableMallocCheckSize(ptr, 4*minLargeObjectSize);
234*51c0b2f7Stbbdev     REQUIRE(tbb::detail::is_aligned(ptr, 128));
235*51c0b2f7Stbbdev     free_p(ptr);
236*51c0b2f7Stbbdev }
237*51c0b2f7Stbbdev 
238*51c0b2f7Stbbdev void CheckVallocFuncOverload(void *(*valloc_p)(size_t), void (*free_p)(void*))
239*51c0b2f7Stbbdev {
240*51c0b2f7Stbbdev     void *ptr = valloc_p(minLargeObjectSize);
241*51c0b2f7Stbbdev     scalableMallocCheckSize(ptr, minLargeObjectSize);
242*51c0b2f7Stbbdev     REQUIRE(tbb::detail::is_aligned(ptr, sysconf(_SC_PAGESIZE)));
243*51c0b2f7Stbbdev     free_p(ptr);
244*51c0b2f7Stbbdev }
245*51c0b2f7Stbbdev 
246*51c0b2f7Stbbdev void CheckPvalloc(void *(*pvalloc_p)(size_t), void (*free_p)(void*))
247*51c0b2f7Stbbdev {
248*51c0b2f7Stbbdev     const long memoryPageSize = sysconf(_SC_PAGESIZE);
249*51c0b2f7Stbbdev     // request large object with not power-of-2 size
250*51c0b2f7Stbbdev     const size_t largeSz = alignUp(minLargeObjectSize, 16*1024) + 1;
251*51c0b2f7Stbbdev 
252*51c0b2f7Stbbdev     for (size_t sz = 0; sz<=largeSz; sz+=largeSz) {
253*51c0b2f7Stbbdev         void *ptr = pvalloc_p(sz);
254*51c0b2f7Stbbdev         scalableMallocCheckSize(ptr, sz? alignUp(sz, memoryPageSize) : memoryPageSize);
255*51c0b2f7Stbbdev         REQUIRE(tbb::detail::is_aligned(ptr, memoryPageSize));
256*51c0b2f7Stbbdev         free_p(ptr);
257*51c0b2f7Stbbdev     }
258*51c0b2f7Stbbdev }
259*51c0b2f7Stbbdev 
260*51c0b2f7Stbbdev #endif // MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED
261*51c0b2f7Stbbdev 
262*51c0b2f7Stbbdev // regression test: on macOS scalable_free() treated small aligned object,
263*51c0b2f7Stbbdev // placed in large block, as small block
264*51c0b2f7Stbbdev void CheckFreeAligned() {
265*51c0b2f7Stbbdev     size_t sz[] = {8, 4*1024, 16*1024, 0};
266*51c0b2f7Stbbdev     size_t align[] = {8, 4*1024, 16*1024, 0};
267*51c0b2f7Stbbdev 
268*51c0b2f7Stbbdev     for (int s=0; sz[s]; s++)
269*51c0b2f7Stbbdev         for (int a=0; align[a]; a++) {
270*51c0b2f7Stbbdev             void *ptr = NULL;
271*51c0b2f7Stbbdev #if __TBB_POSIX_MEMALIGN_PRESENT
272*51c0b2f7Stbbdev             int ret = posix_memalign(&ptr, align[a], sz[s]);
273*51c0b2f7Stbbdev             REQUIRE(!ret);
274*51c0b2f7Stbbdev #elif MALLOC_WINDOWS_OVERLOAD_ENABLED
275*51c0b2f7Stbbdev             ptr = _aligned_malloc(sz[s], align[a]);
276*51c0b2f7Stbbdev #endif
277*51c0b2f7Stbbdev             REQUIRE(tbb::detail::is_aligned(ptr, align[a]));
278*51c0b2f7Stbbdev             free(ptr);
279*51c0b2f7Stbbdev         }
280*51c0b2f7Stbbdev }
281*51c0b2f7Stbbdev 
282*51c0b2f7Stbbdev #if __ANDROID__
283*51c0b2f7Stbbdev // Workaround for an issue with strdup somehow bypassing our malloc replacement on Android.
284*51c0b2f7Stbbdev char *strdup(const char *str) {
285*51c0b2f7Stbbdev     REPORT( "Known issue: malloc replacement does not work for strdup on Android.\n" );
286*51c0b2f7Stbbdev     size_t len = strlen(str)+1;
287*51c0b2f7Stbbdev     void *new_str = malloc(len);
288*51c0b2f7Stbbdev     return new_str ? reinterpret_cast<char *>(memcpy(new_str, str, len)) : 0;
289*51c0b2f7Stbbdev }
290*51c0b2f7Stbbdev #endif
291*51c0b2f7Stbbdev 
292*51c0b2f7Stbbdev #if __APPLE__
293*51c0b2f7Stbbdev #include <mach/mach.h>
294*51c0b2f7Stbbdev 
295*51c0b2f7Stbbdev // regression test: malloc_usable_size() that was passed to zone interface
296*51c0b2f7Stbbdev // called system malloc_usable_size(), so for object that was not allocated
297*51c0b2f7Stbbdev // by tbbmalloc non-zero was returned, so such objects were passed to
298*51c0b2f7Stbbdev // tbbmalloc's free(), that is incorrect
299*51c0b2f7Stbbdev void TestZoneOverload() {
300*51c0b2f7Stbbdev     vm_address_t *zones;
301*51c0b2f7Stbbdev     unsigned zones_num;
302*51c0b2f7Stbbdev 
303*51c0b2f7Stbbdev     kern_return_t ret = malloc_get_all_zones(mach_task_self(), NULL, &zones, &zones_num);
304*51c0b2f7Stbbdev     REQUIRE((!ret && zones_num>1));
305*51c0b2f7Stbbdev     malloc_zone_t *sys_zone = (malloc_zone_t*)zones[1];
306*51c0b2f7Stbbdev     REQUIRE_MESSAGE(strcmp("tbbmalloc", malloc_get_zone_name(sys_zone)), "zone 1 expected to be not tbbmalloc");
307*51c0b2f7Stbbdev     void *p = malloc_zone_malloc(sys_zone, 16);
308*51c0b2f7Stbbdev     free(p);
309*51c0b2f7Stbbdev }
310*51c0b2f7Stbbdev #else
311*51c0b2f7Stbbdev #define TestZoneOverload()
312*51c0b2f7Stbbdev #endif
313*51c0b2f7Stbbdev 
314*51c0b2f7Stbbdev #if _WIN32
315*51c0b2f7Stbbdev // regression test: certain MSVC runtime functions use "public" allocation functions
316*51c0b2f7Stbbdev // but internal free routines, causing crashes if tbbmalloc_proxy does not intercept the latter.
317*51c0b2f7Stbbdev void TestRuntimeRoutines() {
318*51c0b2f7Stbbdev     system("rem should be a safe command to call");
319*51c0b2f7Stbbdev }
320*51c0b2f7Stbbdev #else
321*51c0b2f7Stbbdev #define TestRuntimeRoutines()
322*51c0b2f7Stbbdev #endif
323*51c0b2f7Stbbdev 
324*51c0b2f7Stbbdev struct BigStruct {
325*51c0b2f7Stbbdev     char f[minLargeObjectSize];
326*51c0b2f7Stbbdev };
327*51c0b2f7Stbbdev 
328*51c0b2f7Stbbdev void CheckNewDeleteOverload() {
329*51c0b2f7Stbbdev     BigStruct *s1, *s2, *s3, *s4;
330*51c0b2f7Stbbdev 
331*51c0b2f7Stbbdev     s1 = new BigStruct;
332*51c0b2f7Stbbdev     scalableMallocCheckSize(s1, sizeof(BigStruct));
333*51c0b2f7Stbbdev     delete s1;
334*51c0b2f7Stbbdev 
335*51c0b2f7Stbbdev     s2 = new BigStruct[10];
336*51c0b2f7Stbbdev     scalableMallocCheckSize(s2, 10*sizeof(BigStruct));
337*51c0b2f7Stbbdev     delete []s2;
338*51c0b2f7Stbbdev 
339*51c0b2f7Stbbdev     s3 = new(std::nothrow) BigStruct;
340*51c0b2f7Stbbdev     scalableMallocCheckSize(s3, sizeof(BigStruct));
341*51c0b2f7Stbbdev     delete s3;
342*51c0b2f7Stbbdev 
343*51c0b2f7Stbbdev     s4 = new(std::nothrow) BigStruct[2];
344*51c0b2f7Stbbdev     scalableMallocCheckSize(s4, 2*sizeof(BigStruct));
345*51c0b2f7Stbbdev     delete []s4;
346*51c0b2f7Stbbdev }
347*51c0b2f7Stbbdev 
348*51c0b2f7Stbbdev #if MALLOC_WINDOWS_OVERLOAD_ENABLED
349*51c0b2f7Stbbdev void FuncReplacementInfoCheck() {
350*51c0b2f7Stbbdev     char **func_replacement_log;
351*51c0b2f7Stbbdev     int func_replacement_status = TBB_malloc_replacement_log(&func_replacement_log);
352*51c0b2f7Stbbdev 
353*51c0b2f7Stbbdev     std::set<std::string> functions;
354*51c0b2f7Stbbdev     functions.insert("free");
355*51c0b2f7Stbbdev     functions.insert("_msize");
356*51c0b2f7Stbbdev     functions.insert("_aligned_free");
357*51c0b2f7Stbbdev     functions.insert("_aligned_msize");
358*51c0b2f7Stbbdev 
359*51c0b2f7Stbbdev     int status_check = 0;
360*51c0b2f7Stbbdev     for (char** log_string = func_replacement_log; *log_string != 0; log_string++) {
361*51c0b2f7Stbbdev         std::stringstream s(*log_string);
362*51c0b2f7Stbbdev         std::string status, function_name;
363*51c0b2f7Stbbdev         s >> status >> function_name;
364*51c0b2f7Stbbdev 
365*51c0b2f7Stbbdev         if (status.find("Fail:") != status.npos) {
366*51c0b2f7Stbbdev             status_check = -1;
367*51c0b2f7Stbbdev         }
368*51c0b2f7Stbbdev 
369*51c0b2f7Stbbdev         functions.erase(function_name);
370*51c0b2f7Stbbdev     }
371*51c0b2f7Stbbdev 
372*51c0b2f7Stbbdev     REQUIRE_MESSAGE(functions.empty(), "Changed opcodes log must contain all required functions with \"Success\" changed status");
373*51c0b2f7Stbbdev     REQUIRE_MESSAGE(func_replacement_status == status_check, "replacement_opcodes_log() function return wrong status");
374*51c0b2f7Stbbdev 
375*51c0b2f7Stbbdev     func_replacement_status = TBB_malloc_replacement_log(NULL);
376*51c0b2f7Stbbdev     REQUIRE_MESSAGE(func_replacement_status == status_check, "replacement_opcodes_log() function return wrong status");
377*51c0b2f7Stbbdev 
378*51c0b2f7Stbbdev     // TODO: was ASSERT_WARNING
379*51c0b2f7Stbbdev     if (func_replacement_status != 0) {
380*51c0b2f7Stbbdev         REPORT("Some standard allocation functions was not replaced to tbb_malloc functions.\n");
381*51c0b2f7Stbbdev     }
382*51c0b2f7Stbbdev }
383*51c0b2f7Stbbdev #endif // MALLOC_WINDOWS_OVERLOAD_ENABLED
384*51c0b2f7Stbbdev 
385*51c0b2f7Stbbdev //! Testing tbbmalloc_proxy overload capabilities
386*51c0b2f7Stbbdev //! \brief \ref error_guessing
387*51c0b2f7Stbbdev TEST_CASE("Main set of tests") {
388*51c0b2f7Stbbdev     void *ptr = NULL;
389*51c0b2f7Stbbdev     utils::suppress_unused_warning(ptr); // for android
390*51c0b2f7Stbbdev 
391*51c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED
392*51c0b2f7Stbbdev     REQUIRE_MESSAGE(dlsym(RTLD_DEFAULT, "scalable_malloc"), "Lost dependency on malloc_proxy or LD_PRELOAD was not set?");
393*51c0b2f7Stbbdev #endif
394*51c0b2f7Stbbdev 
395*51c0b2f7Stbbdev /* On Windows, memory block size returned by _msize() is sometimes used
396*51c0b2f7Stbbdev    to calculate the size for an extended block. Substituting _msize,
397*51c0b2f7Stbbdev    scalable_msize initially returned 0 for regions not allocated by the scalable
398*51c0b2f7Stbbdev    allocator, which led to incorrect memory reallocation and subsequent crashes.
399*51c0b2f7Stbbdev    It was found that adding a new environment variable triggers the error.
400*51c0b2f7Stbbdev */
401*51c0b2f7Stbbdev     REQUIRE_MESSAGE(getenv("PATH"), "We assume that PATH is set everywhere.");
402*51c0b2f7Stbbdev     char *pathCopy = strdup(getenv("PATH"));
403*51c0b2f7Stbbdev #if __ANDROID__
404*51c0b2f7Stbbdev     REQUIRE_MESSAGE(strcmp(pathCopy,getenv("PATH")) == 0, "strdup workaround does not work as expected.");
405*51c0b2f7Stbbdev #endif
406*51c0b2f7Stbbdev     const char *newEnvName = "__TBBMALLOC_OVERLOAD_REGRESSION_TEST_FOR_REALLOC_AND_MSIZE";
407*51c0b2f7Stbbdev     REQUIRE_MESSAGE(!getenv(newEnvName), "Environment variable should not be used before.");
408*51c0b2f7Stbbdev     int r = utils::SetEnv(newEnvName,"1");
409*51c0b2f7Stbbdev     REQUIRE(!r);
410*51c0b2f7Stbbdev     char *path = getenv("PATH");
411*51c0b2f7Stbbdev     REQUIRE_MESSAGE((path && 0==strcmp(path, pathCopy)), "Environment was changed erroneously.");
412*51c0b2f7Stbbdev     free(pathCopy);
413*51c0b2f7Stbbdev 
414*51c0b2f7Stbbdev     CheckStdFuncOverload(malloc, calloc, realloc, free);
415*51c0b2f7Stbbdev #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED
416*51c0b2f7Stbbdev 
417*51c0b2f7Stbbdev #if __TBB_POSIX_MEMALIGN_PRESENT
418*51c0b2f7Stbbdev     int ret = posix_memalign(&ptr, 1024, 3*minLargeObjectSize);
419*51c0b2f7Stbbdev     REQUIRE(0 == ret);
420*51c0b2f7Stbbdev     scalableMallocCheckSize(ptr, 3*minLargeObjectSize);
421*51c0b2f7Stbbdev     REQUIRE(tbb::detail::is_aligned(ptr, 1024));
422*51c0b2f7Stbbdev     free(ptr);
423*51c0b2f7Stbbdev #endif
424*51c0b2f7Stbbdev 
425*51c0b2f7Stbbdev #if __TBB_VALLOC_PRESENT
426*51c0b2f7Stbbdev     CheckVallocFuncOverload(valloc, free);
427*51c0b2f7Stbbdev #endif
428*51c0b2f7Stbbdev #if __TBB_PVALLOC_PRESENT
429*51c0b2f7Stbbdev     CheckPvalloc(pvalloc, free);
430*51c0b2f7Stbbdev #endif
431*51c0b2f7Stbbdev #if __linux__
432*51c0b2f7Stbbdev     CheckMemalignFuncOverload(memalign, free);
433*51c0b2f7Stbbdev #if __TBB_ALIGNED_ALLOC_PRESENT
434*51c0b2f7Stbbdev     CheckMemalignFuncOverload(aligned_alloc, free);
435*51c0b2f7Stbbdev #endif
436*51c0b2f7Stbbdev 
437*51c0b2f7Stbbdev     struct mallinfo info = mallinfo();
438*51c0b2f7Stbbdev     // right now mallinfo initialized by zero
439*51c0b2f7Stbbdev     REQUIRE((!info.arena && !info.ordblks && !info.smblks && !info.hblks
440*51c0b2f7Stbbdev            && !info.hblkhd && !info.usmblks && !info.fsmblks
441*51c0b2f7Stbbdev            && !info.uordblks && !info.fordblks && !info.keepcost));
442*51c0b2f7Stbbdev 
443*51c0b2f7Stbbdev  #if !__ANDROID__
444*51c0b2f7Stbbdev     // These non-standard functions are exported by GLIBC, and might be used
445*51c0b2f7Stbbdev     // in conjunction with standard malloc/free. Test that we overload them as well.
446*51c0b2f7Stbbdev     // Bionic doesn't have them.
447*51c0b2f7Stbbdev     CheckStdFuncOverload(__libc_malloc, __libc_calloc, __libc_realloc, __libc_free);
448*51c0b2f7Stbbdev     CheckMemalignFuncOverload(__libc_memalign, __libc_free);
449*51c0b2f7Stbbdev     CheckVallocFuncOverload(__libc_valloc, __libc_free);
450*51c0b2f7Stbbdev     CheckPvalloc(__libc_pvalloc, __libc_free);
451*51c0b2f7Stbbdev  #endif
452*51c0b2f7Stbbdev #endif // __linux__
453*51c0b2f7Stbbdev 
454*51c0b2f7Stbbdev #else // MALLOC_WINDOWS_OVERLOAD_ENABLED
455*51c0b2f7Stbbdev 
456*51c0b2f7Stbbdev     ptr = _aligned_malloc(minLargeObjectSize, 16);
457*51c0b2f7Stbbdev     scalableMallocCheckSize(ptr, minLargeObjectSize);
458*51c0b2f7Stbbdev     REQUIRE(tbb::detail::is_aligned(ptr, 16));
459*51c0b2f7Stbbdev 
460*51c0b2f7Stbbdev     // Testing of workaround for vs "is power of 2 pow N" bug that accepts zeros
461*51c0b2f7Stbbdev     void* ptr1 = _aligned_malloc(minLargeObjectSize, 0);
462*51c0b2f7Stbbdev     scalableMallocCheckSize(ptr, minLargeObjectSize);
463*51c0b2f7Stbbdev     REQUIRE(tbb::detail::is_aligned(ptr, sizeof(void*)));
464*51c0b2f7Stbbdev     _aligned_free(ptr1);
465*51c0b2f7Stbbdev 
466*51c0b2f7Stbbdev     ptr1 = _aligned_realloc(ptr, minLargeObjectSize*10, 16);
467*51c0b2f7Stbbdev     scalableMallocCheckSize(ptr1, minLargeObjectSize*10);
468*51c0b2f7Stbbdev     REQUIRE(tbb::detail::is_aligned(ptr, 16));
469*51c0b2f7Stbbdev     _aligned_free(ptr1);
470*51c0b2f7Stbbdev 
471*51c0b2f7Stbbdev     FuncReplacementInfoCheck();
472*51c0b2f7Stbbdev 
473*51c0b2f7Stbbdev #endif
474*51c0b2f7Stbbdev     CheckFreeAligned();
475*51c0b2f7Stbbdev 
476*51c0b2f7Stbbdev     CheckNewDeleteOverload();
477*51c0b2f7Stbbdev 
478*51c0b2f7Stbbdev #if _WIN32
479*51c0b2f7Stbbdev     std::string stdstring = "dependency on msvcpXX.dll";
480*51c0b2f7Stbbdev     REQUIRE(strcmp(stdstring.c_str(), "dependency on msvcpXX.dll") == 0);
481*51c0b2f7Stbbdev #endif
482*51c0b2f7Stbbdev     TestZoneOverload();
483*51c0b2f7Stbbdev     TestRuntimeRoutines();
484*51c0b2f7Stbbdev }
485*51c0b2f7Stbbdev #endif // !HARNESS_SKIP_TEST
486