1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <fcntl.h>
30 #include <malloc.h>
31 #include <stdlib.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <unistd.h>
35
36 #include <string>
37 #include <vector>
38
39 #include <gtest/gtest.h>
40
41 #include <bionic/malloc.h>
42 #include <private/bionic_malloc_dispatch.h>
43 #include <tests/utils.h>
44
45 __BEGIN_DECLS
46
47 void get_malloc_leak_info(uint8_t**, size_t*, size_t*, size_t*, size_t*);
48 void free_malloc_leak_info(uint8_t*);
49 int malloc_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*);
50 void malloc_enable();
51 void malloc_disable();
52 ssize_t malloc_backtrace(void*, uintptr_t*, size_t);
53
54 __END_DECLS
55
56 class MallocHooksTest : public ::testing::Test {
57 protected:
SetUp()58 void SetUp() override {
59 ASSERT_EQ(0, setenv("LIBC_HOOKS_ENABLE", "1", true));
60 initialized_ = false;
61 }
62
TearDown()63 void TearDown() override {
64 if (initialized_) {
65 Reset();
66 }
67 ASSERT_EQ(0, unsetenv("LIBC_HOOKS_ENABLE"));
68 }
69
Init()70 void Init() {
71 initialized_ = true;
72 malloc_hook_called_ = false;
73 free_hook_called_ = false;
74 realloc_hook_called_ = false;
75 memalign_hook_called_ = false;
76
77 void_arg_ = nullptr;
78
79 orig_malloc_hook_ = __malloc_hook;
80 orig_free_hook_ = __free_hook;
81 orig_realloc_hook_ = __realloc_hook;
82 orig_memalign_hook_ = __memalign_hook;
83 }
84
Reset()85 void Reset() {
86 __malloc_hook = orig_malloc_hook_;
87 __free_hook = orig_free_hook_;
88 __realloc_hook = orig_realloc_hook_;
89 __memalign_hook = orig_memalign_hook_;
90 }
91
92 void Exec(std::vector<const char*> args);
93 void RunTest(std::string test_name);
94
95 public:
96 bool initialized_;
97
98 int fd_;
99 std::string raw_output_;
100 pid_t pid_;
101
102 static bool malloc_hook_called_;
103 static bool free_hook_called_;
104 static bool realloc_hook_called_;
105 static bool memalign_hook_called_;
106 static const void* void_arg_;
107
108 static void* (*orig_malloc_hook_)(size_t, const void*);
109 static void (*orig_free_hook_)(void*, const void*);
110 static void* (*orig_realloc_hook_)(void*, size_t, const void*);
111 static void* (*orig_memalign_hook_)(size_t, size_t, const void*);
112
113 static void* test_malloc_hook(size_t, const void*);
114 static void* test_realloc_hook(void* ptr, size_t, const void*);
115 static void* test_memalign_hook(size_t, size_t, const void*);
116 static void test_free_hook(void*, const void*);
117 };
118
119 bool MallocHooksTest::malloc_hook_called_;
120 bool MallocHooksTest::free_hook_called_;
121 bool MallocHooksTest::realloc_hook_called_;
122 bool MallocHooksTest::memalign_hook_called_;
123 const void* MallocHooksTest::void_arg_;
124
125 void* (*MallocHooksTest::orig_malloc_hook_)(size_t, const void*);
126 void (*MallocHooksTest::orig_free_hook_)(void*, const void*);
127 void* (*MallocHooksTest::orig_realloc_hook_)(void*, size_t, const void*);
128 void* (*MallocHooksTest::orig_memalign_hook_)(size_t, size_t, const void*);
129
GetExe(std::string * exe_name)130 static void GetExe(std::string* exe_name) {
131 char path[PATH_MAX];
132 ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
133 ASSERT_TRUE(path_len >= 0);
134 *exe_name = std::string(path, path_len);
135 }
136
RunTest(std::string test_name)137 void MallocHooksTest::RunTest(std::string test_name) {
138 std::vector<const char*> args;
139 args.push_back("--gtest_also_run_disabled_tests");
140 std::string filter_arg("--gtest_filter=" + test_name);
141 args.push_back(filter_arg.c_str());
142
143 ExecTestHelper test;
144 test.Run(
145 [&]() {
146 std::string exe_name;
147 GetExe(&exe_name);
148 args.insert(args.begin(), exe_name.c_str());
149 args.push_back(nullptr);
150 execv(args[0], reinterpret_cast<char* const*>(const_cast<char**>(args.data())));
151 exit(1);
152 },
153 0, nullptr);
154 }
155
test_malloc_hook(size_t size,const void * arg)156 void* MallocHooksTest::test_malloc_hook(size_t size, const void* arg) {
157 malloc_hook_called_ = true;
158 void_arg_ = arg;
159 return orig_malloc_hook_(size, arg);
160 }
161
test_realloc_hook(void * ptr,size_t size,const void * arg)162 void* MallocHooksTest::test_realloc_hook(void* ptr, size_t size, const void* arg) {
163 realloc_hook_called_ = true;
164 void_arg_ = arg;
165 return orig_realloc_hook_(ptr, size, arg);
166 }
167
test_memalign_hook(size_t alignment,size_t size,const void * arg)168 void* MallocHooksTest::test_memalign_hook(size_t alignment, size_t size, const void* arg) {
169 memalign_hook_called_ = true;
170 void_arg_ = arg;
171 return orig_memalign_hook_(alignment, size, arg);
172 }
173
test_free_hook(void * ptr,const void * arg)174 void MallocHooksTest::test_free_hook(void* ptr, const void* arg) {
175 free_hook_called_ = true;
176 void_arg_ = arg;
177 return orig_free_hook_(ptr, arg);
178 }
179
TEST_F(MallocHooksTest,other_malloc_functions)180 TEST_F(MallocHooksTest, other_malloc_functions) {
181 RunTest("*.DISABLED_other_malloc_functions");
182 }
183
184 // Call other intercepted functions to make sure there are no crashes.
TEST_F(MallocHooksTest,DISABLED_other_malloc_functions)185 TEST_F(MallocHooksTest, DISABLED_other_malloc_functions) {
186 struct mallinfo info = mallinfo();
187 EXPECT_NE(0U, info.uordblks);
188
189 EXPECT_EQ(0, mallopt(-1000, -1000));
190
191 void* ptr = malloc(1024);
192 EXPECT_LE(1024U, malloc_usable_size(ptr));
193 free(ptr);
194 }
195
TEST_F(MallocHooksTest,extended_functions)196 TEST_F(MallocHooksTest, extended_functions) {
197 RunTest("*.DISABLED_extended_functions");
198 }
199
TEST_F(MallocHooksTest,DISABLED_extended_functions)200 TEST_F(MallocHooksTest, DISABLED_extended_functions) {
201 android_mallopt_leak_info_t leak_info;
202 ASSERT_TRUE(android_mallopt(M_GET_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info)));
203 EXPECT_EQ(nullptr, leak_info.buffer);
204 EXPECT_EQ(0U, leak_info.overall_size);
205 EXPECT_EQ(0U, leak_info.info_size);
206 EXPECT_EQ(0U, leak_info.total_memory);
207 EXPECT_EQ(0U, leak_info.backtrace_size);
208
209 ASSERT_TRUE(android_mallopt(M_FREE_MALLOC_LEAK_INFO, &leak_info, sizeof(leak_info)));
210
211 malloc_enable();
212 malloc_disable();
213
214 EXPECT_EQ(0, malloc_iterate(0, 0, nullptr, nullptr));
215
216 // Malloc hooks doesn't support any backtracing.
217 EXPECT_EQ(0, malloc_backtrace(nullptr, nullptr, 10));
218 }
219
TEST_F(MallocHooksTest,malloc_hook)220 TEST_F(MallocHooksTest, malloc_hook) {
221 RunTest("*.DISABLED_malloc_hook");
222 }
223
TEST_F(MallocHooksTest,DISABLED_malloc_hook)224 TEST_F(MallocHooksTest, DISABLED_malloc_hook) {
225 Init();
226 ASSERT_TRUE(__malloc_hook != nullptr);
227 __malloc_hook = test_malloc_hook;
228
229 void* ptr = malloc(1024);
230 ASSERT_TRUE(ptr != nullptr);
231 write(0, ptr, 0);
232 free(ptr);
233
234 EXPECT_TRUE(malloc_hook_called_) << "The malloc hook was not called.";
235 EXPECT_TRUE(void_arg_ != nullptr) << "The malloc hook was called with a nullptr.";
236 }
237
TEST_F(MallocHooksTest,free_hook)238 TEST_F(MallocHooksTest, free_hook) {
239 RunTest("*.DISABLED_free_hook");
240 }
241
TEST_F(MallocHooksTest,DISABLED_free_hook)242 TEST_F(MallocHooksTest, DISABLED_free_hook) {
243 Init();
244 ASSERT_TRUE(__free_hook != nullptr);
245 __free_hook = test_free_hook;
246
247 void* ptr = malloc(1024);
248 ASSERT_TRUE(ptr != nullptr);
249 free(ptr);
250 write(0, ptr, 0);
251
252 EXPECT_TRUE(free_hook_called_) << "The free hook was not called.";
253 EXPECT_TRUE(void_arg_ != nullptr) << "The free hook was called with a nullptr.";
254 }
255
TEST_F(MallocHooksTest,realloc_hook)256 TEST_F(MallocHooksTest, realloc_hook) {
257 RunTest("*.DISABLED_realloc_hook");
258 }
259
TEST_F(MallocHooksTest,DISABLED_realloc_hook)260 TEST_F(MallocHooksTest, DISABLED_realloc_hook) {
261 Init();
262 ASSERT_TRUE(__realloc_hook != nullptr);
263 __realloc_hook = test_realloc_hook;
264
265 void* ptr = malloc(1024);
266 ASSERT_TRUE(ptr != nullptr);
267 ptr = realloc(ptr, 2048);
268 free(ptr);
269 write(0, ptr, 0);
270
271 EXPECT_TRUE(realloc_hook_called_) << "The realloc hook was not called.";
272 EXPECT_TRUE(void_arg_ != nullptr) << "The realloc hook was called with a nullptr.";
273 }
274
TEST_F(MallocHooksTest,memalign_hook)275 TEST_F(MallocHooksTest, memalign_hook) {
276 RunTest("*.DISABLED_memalign_hook");
277 }
278
TEST_F(MallocHooksTest,DISABLED_memalign_hook)279 TEST_F(MallocHooksTest, DISABLED_memalign_hook) {
280 Init();
281 ASSERT_TRUE(__memalign_hook != nullptr);
282 __memalign_hook = test_memalign_hook;
283
284 void* ptr = memalign(32, 1024);
285 ASSERT_TRUE(ptr != nullptr);
286 free(ptr);
287 write(0, ptr, 0);
288
289 EXPECT_TRUE(memalign_hook_called_) << "The memalign hook was not called.";
290 EXPECT_TRUE(void_arg_ != nullptr) << "The memalign hook was called with a nullptr.";
291 }
292
TEST_F(MallocHooksTest,posix_memalign_hook)293 TEST_F(MallocHooksTest, posix_memalign_hook) {
294 RunTest("*.DISABLED_posix_memalign_hook");
295 }
296
TEST_F(MallocHooksTest,DISABLED_posix_memalign_hook)297 TEST_F(MallocHooksTest, DISABLED_posix_memalign_hook) {
298 Init();
299 ASSERT_TRUE(__memalign_hook != nullptr);
300 __memalign_hook = test_memalign_hook;
301
302 void* ptr;
303 ASSERT_EQ(0, posix_memalign(&ptr, 32, 1024));
304 ASSERT_TRUE(ptr != nullptr);
305 free(ptr);
306 write(0, ptr, 0);
307
308 EXPECT_TRUE(memalign_hook_called_) << "The memalign hook was not called when running posix_memalign.";
309 EXPECT_TRUE(void_arg_ != nullptr) << "The memalign hook was called with a nullptr.";
310 }
311
TEST_F(MallocHooksTest,posix_memalign_hook_error)312 TEST_F(MallocHooksTest, posix_memalign_hook_error) {
313 RunTest("*.DISABLED_posix_memalign_hook_error");
314 }
315
TEST_F(MallocHooksTest,DISABLED_posix_memalign_hook_error)316 TEST_F(MallocHooksTest, DISABLED_posix_memalign_hook_error) {
317 Init();
318 ASSERT_TRUE(__memalign_hook != nullptr);
319 __memalign_hook = test_memalign_hook;
320
321 void* ptr;
322 ASSERT_EQ(EINVAL, posix_memalign(&ptr, 11, 1024));
323 write(0, ptr, 0);
324
325 EXPECT_FALSE(memalign_hook_called_)
326 << "The memalign hook was called when running posix_memalign with an error.";
327 EXPECT_FALSE(void_arg_ != nullptr)
328 << "The memalign hook was called with a nullptr with an error.";
329 }
330
TEST_F(MallocHooksTest,aligned_alloc_hook)331 TEST_F(MallocHooksTest, aligned_alloc_hook) {
332 RunTest("*.DISABLED_aligned_alloc_hook");
333 }
334
TEST_F(MallocHooksTest,DISABLED_aligned_alloc_hook)335 TEST_F(MallocHooksTest, DISABLED_aligned_alloc_hook) {
336 Init();
337 ASSERT_TRUE(__memalign_hook != nullptr);
338 __memalign_hook = test_memalign_hook;
339
340 void* ptr = aligned_alloc(32, 1024);
341 ASSERT_TRUE(ptr != nullptr);
342 free(ptr);
343 write(0, ptr, 0);
344
345 EXPECT_TRUE(memalign_hook_called_) << "The memalign hook was not called when running aligned_alloc.";
346 EXPECT_TRUE(void_arg_ != nullptr) << "The memalign hook was called with a nullptr.";
347 }
348
TEST_F(MallocHooksTest,aligned_alloc_hook_error)349 TEST_F(MallocHooksTest, aligned_alloc_hook_error) {
350 RunTest("*.DISABLED_aligned_alloc_hook_error");
351 }
352
TEST_F(MallocHooksTest,DISABLED_aligned_alloc_hook_error)353 TEST_F(MallocHooksTest, DISABLED_aligned_alloc_hook_error) {
354 Init();
355 ASSERT_TRUE(__memalign_hook != nullptr);
356 __memalign_hook = test_memalign_hook;
357
358 void* ptr = aligned_alloc(11, 1024);
359 ASSERT_TRUE(ptr == nullptr);
360 EXPECT_EQ(EINVAL, errno);
361 write(0, ptr, 0);
362
363 EXPECT_FALSE(memalign_hook_called_)
364 << "The memalign hook was called when running aligned_alloc with an error.";
365 EXPECT_FALSE(void_arg_ != nullptr)
366 << "The memalign hook was called with a nullptr with an error.";
367 }
368
369 #if !defined(__LP64__)
TEST_F(MallocHooksTest,pvalloc_hook)370 TEST_F(MallocHooksTest, pvalloc_hook) {
371 RunTest("*.DISABLED_pvalloc_hook");
372 }
373
374 extern "C" void* pvalloc(size_t);
375
TEST_F(MallocHooksTest,DISABLED_pvalloc_hook)376 TEST_F(MallocHooksTest, DISABLED_pvalloc_hook) {
377 Init();
378 ASSERT_TRUE(__memalign_hook != nullptr);
379 __memalign_hook = test_memalign_hook;
380
381 void* ptr = pvalloc(1024);
382 ASSERT_TRUE(ptr != nullptr);
383 write(0, ptr, 0);
384 free(ptr);
385
386 EXPECT_TRUE(memalign_hook_called_) << "The memalign hook was not called for pvalloc.";
387 EXPECT_TRUE(void_arg_ != nullptr) << "The memalign hook was called with a nullptr.";
388 }
389
TEST_F(MallocHooksTest,valloc_hook)390 TEST_F(MallocHooksTest, valloc_hook) {
391 RunTest("*.DISABLED_valloc_hook");
392 }
393
394 extern "C" void* valloc(size_t);
395
TEST_F(MallocHooksTest,DISABLED_valloc_hook)396 TEST_F(MallocHooksTest, DISABLED_valloc_hook) {
397 Init();
398 ASSERT_TRUE(__memalign_hook != nullptr);
399 __memalign_hook = test_memalign_hook;
400
401 void* ptr = valloc(1024);
402 ASSERT_TRUE(ptr != nullptr);
403 write(0, ptr, 0);
404 free(ptr);
405
406 EXPECT_TRUE(memalign_hook_called_) << "The memalign hook was not called for valloc.";
407 EXPECT_TRUE(void_arg_ != nullptr) << "The memalign hook was called with a nullptr.";
408 }
409 #endif
410