1/*
2 Copyright (c) 2005-2019 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#include <stdlib.h>
26#include "harness_allocator_overload.h"
27
28// __TBB_malloc_safer_msize() returns 0 for unknown objects,
29// thus we can detect ownership
30#if _USRDLL
31 #if _WIN32||_WIN64
32extern __declspec(dllexport)
33 #endif
34bool dll_isMallocOverloaded()
35#else
36bool exe_isMallocOverloaded()
37#endif
38{
39 const size_t reqSz = 8;
40 void *o = malloc(reqSz);
41 bool ret = __TBB_malloc_safer_msize(o, NULL) >= reqSz;
42 free(o);
43 return ret;
44}
45
46#if _USRDLL
47
48#if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED
49
50#define HARNESS_CUSTOM_MAIN 1
51#include "harness.h"
52
53#include <dlfcn.h>
54#if __APPLE__
55#include <malloc/malloc.h>
56#define malloc_usable_size(p) malloc_size(p)
57#else
58#include <malloc.h>
59#endif
60#include <signal.h>
61
62#if __linux__ && !__ANDROID__
63extern "C" {
64void __libc_free(void *ptr);
65void *__libc_realloc(void *ptr, size_t size);
66
67// check that such kind of free/realloc overload works correctly
68void free(void *ptr)
69{
70 __libc_free(ptr);
71}
72
73void *realloc(void *ptr, size_t size)
74{
75 return __libc_realloc(ptr, size);
76}
77} // extern "C"
78#endif // __linux__ && !__ANDROID__
79
80#endif // MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED
81
82// Even when the test is skipped, dll source must not be empty to generate .lib to link with.
83
84#ifndef _PGO_INSTRUMENT
85void dummyFunction() {}
86
87// TODO: enable the check under Android
88#if (MALLOC_UNIXLIKE_OVERLOAD_ENABLED || MALLOC_ZONE_OVERLOAD_ENABLED) && !__ANDROID__
89typedef void *(malloc_type)(size_t);
90
91static void SigSegv(int)
92{
93 REPORT("Known issue: SIGSEGV during work with memory allocated by replaced allocator.\n"
94 "skip\n");
95 exit(0);
96}
97
98// TODO: Using of SIGSEGV can be eliminated via parsing /proc/self/maps
99// and series of system malloc calls.
100void TestReplacedAllocFunc()
101{
102 struct sigaction sa, sa_default;
103 malloc_type *orig_malloc = (malloc_type*)dlsym(RTLD_NEXT, "malloc");
104 void *p = (*orig_malloc)(16);
105
106 // protect potentially unsafe actions
107 sigemptyset(&sa.sa_mask);
108 sa.sa_flags = 0;
109 sa.sa_handler = SigSegv;
110 if (sigaction(SIGSEGV, &sa, &sa_default))
111 ASSERT(0, "sigaction failed");
112
113 ASSERT(malloc_usable_size(p) >= 16, NULL);
114 free(p);
115 // no more unsafe actions, restore SIGSEGV
116 if (sigaction(SIGSEGV, &sa_default, NULL))
117 ASSERT(0, "sigaction failed");
118}
119#else
120void TestReplacedAllocFunc() { }
121#endif
122
123class Foo {
124public:
125 Foo() {
126 // add a lot of exit handlers to cause memory allocation
127 for (int i=0; i<1024; i++)
128 atexit(dummyFunction);
129 TestReplacedAllocFunc();
130 }
131};
132
133static Foo f;
134#endif
135
136#else // _USRDLL
137#include "harness.h"
138
139#if _WIN32||_WIN64
140#include "tbb/tbbmalloc_proxy.h"
141
142extern __declspec(dllimport)
143#endif
144bool dll_isMallocOverloaded();
145
146int TestMain () {
147#ifdef _PGO_INSTRUMENT
148 REPORT("Known issue: test_malloc_atexit hangs if compiled with -prof-genx\n");
149 return Harness::Skipped;
150#else
151 ASSERT( dll_isMallocOverloaded(), "malloc was not replaced" );
152 ASSERT( exe_isMallocOverloaded(), "malloc was not replaced" );
153 return Harness::Done;
154#endif
155}
156
157#endif // _USRDLL
158