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 <private/bionic_malloc_dispatch.h>
42 #include <tests/utils.h>
43 
44 __BEGIN_DECLS
45 
46 void get_malloc_leak_info(uint8_t**, size_t*, size_t*, size_t*, size_t*);
47 void free_malloc_leak_info(uint8_t*);
48 int malloc_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*);
49 void malloc_enable();
50 void malloc_disable();
51 ssize_t malloc_backtrace(void*, uintptr_t*, size_t);
52 
53 __END_DECLS
54 
55 class MallocHooksTest : public ::testing::Test {
56  protected:
SetUp()57   void SetUp() override {
58     ASSERT_EQ(0, setenv("LIBC_HOOKS_ENABLE", "1", true));
59     initialized_ = false;
60   }
61 
TearDown()62   void TearDown() override {
63     if (initialized_) {
64       Reset();
65     }
66     ASSERT_EQ(0, unsetenv("LIBC_HOOKS_ENABLE"));
67   }
68 
Init()69   void Init() {
70     initialized_ = true;
71     malloc_hook_called_ = false;
72     free_hook_called_ = false;
73     realloc_hook_called_ = false;
74     memalign_hook_called_ = false;
75 
76     void_arg_ = nullptr;
77 
78     orig_malloc_hook_ = __malloc_hook;
79     orig_free_hook_ = __free_hook;
80     orig_realloc_hook_ = __realloc_hook;
81     orig_memalign_hook_ = __memalign_hook;
82   }
83 
Reset()84   void Reset() {
85     __malloc_hook = orig_malloc_hook_;
86     __free_hook = orig_free_hook_;
87     __realloc_hook = orig_realloc_hook_;
88     __memalign_hook = orig_memalign_hook_;
89   }
90 
91   void Exec(std::vector<const char*> args);
92   void RunTest(std::string test_name);
93 
94  public:
95   bool initialized_;
96 
97   int fd_;
98   std::string raw_output_;
99   pid_t pid_;
100 
101   static bool malloc_hook_called_;
102   static bool free_hook_called_;
103   static bool realloc_hook_called_;
104   static bool memalign_hook_called_;
105   static const void* void_arg_;
106 
107   static void* (*orig_malloc_hook_)(size_t, const void*);
108   static void (*orig_free_hook_)(void*, const void*);
109   static void* (*orig_realloc_hook_)(void*, size_t, const void*);
110   static void* (*orig_memalign_hook_)(size_t, size_t, const void*);
111 
112   static void* test_malloc_hook(size_t, const void*);
113   static void* test_realloc_hook(void* ptr, size_t, const void*);
114   static void* test_memalign_hook(size_t, size_t, const void*);
115   static void test_free_hook(void*, const void*);
116 };
117 
118 bool MallocHooksTest::malloc_hook_called_;
119 bool MallocHooksTest::free_hook_called_;
120 bool MallocHooksTest::realloc_hook_called_;
121 bool MallocHooksTest::memalign_hook_called_;
122 const void* MallocHooksTest::void_arg_;
123 
124 void* (*MallocHooksTest::orig_malloc_hook_)(size_t, const void*);
125 void (*MallocHooksTest::orig_free_hook_)(void*, const void*);
126 void* (*MallocHooksTest::orig_realloc_hook_)(void*, size_t, const void*);
127 void* (*MallocHooksTest::orig_memalign_hook_)(size_t, size_t, const void*);
128 
GetExe(std::string * exe_name)129 static void GetExe(std::string* exe_name) {
130   char path[PATH_MAX];
131   ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
132   ASSERT_TRUE(path_len >= 0);
133   *exe_name = std::string(path, path_len);
134 }
135 
RunTest(std::string test_name)136 void MallocHooksTest::RunTest(std::string test_name) {
137   std::vector<const char*> args;
138   args.push_back("--gtest_also_run_disabled_tests");
139   std::string filter_arg("--gtest_filter=" + test_name);
140   args.push_back(filter_arg.c_str());
141 
142   ExecTestHelper test;
143   test.Run(
144       [&]() {
145         std::string exe_name;
146         GetExe(&exe_name);
147         args.insert(args.begin(), exe_name.c_str());
148         args.push_back(nullptr);
149         execv(args[0], reinterpret_cast<char* const*>(const_cast<char**>(args.data())));
150         exit(1);
151       },
152       0, nullptr);
153 }
154 
test_malloc_hook(size_t size,const void * arg)155 void* MallocHooksTest::test_malloc_hook(size_t size, const void* arg) {
156   malloc_hook_called_ = true;
157   void_arg_ = arg;
158   return orig_malloc_hook_(size, arg);
159 }
160 
test_realloc_hook(void * ptr,size_t size,const void * arg)161 void* MallocHooksTest::test_realloc_hook(void* ptr, size_t size, const void* arg) {
162   realloc_hook_called_ = true;
163   void_arg_ = arg;
164   return orig_realloc_hook_(ptr, size, arg);
165 }
166 
test_memalign_hook(size_t alignment,size_t size,const void * arg)167 void* MallocHooksTest::test_memalign_hook(size_t alignment, size_t size, const void* arg) {
168   memalign_hook_called_ = true;
169   void_arg_ = arg;
170   return orig_memalign_hook_(alignment, size, arg);
171 }
172 
test_free_hook(void * ptr,const void * arg)173 void MallocHooksTest::test_free_hook(void* ptr, const void* arg) {
174   free_hook_called_ = true;
175   void_arg_ = arg;
176   return orig_free_hook_(ptr, arg);
177 }
178 
TEST_F(MallocHooksTest,other_malloc_functions)179 TEST_F(MallocHooksTest, other_malloc_functions) {
180   RunTest("*.DISABLED_other_malloc_functions");
181 }
182 
183 // Call other intercepted functions to make sure there are no crashes.
TEST_F(MallocHooksTest,DISABLED_other_malloc_functions)184 TEST_F(MallocHooksTest, DISABLED_other_malloc_functions) {
185   struct mallinfo info = mallinfo();
186   EXPECT_NE(0U, info.uordblks);
187 
188   EXPECT_EQ(0, mallopt(-1000, -1000));
189 
190   void* ptr = malloc(1024);
191   EXPECT_LE(1024U, malloc_usable_size(ptr));
192   free(ptr);
193 }
194 
TEST_F(MallocHooksTest,extended_functions)195 TEST_F(MallocHooksTest, extended_functions) {
196   RunTest("*.DISABLED_extended_functions");
197 }
198 
TEST_F(MallocHooksTest,DISABLED_extended_functions)199 TEST_F(MallocHooksTest, DISABLED_extended_functions) {
200   uint8_t* info = nullptr;
201   size_t overall_size = 100;
202   size_t info_size = 200;
203   size_t total_memory = 300;
204   size_t backtrace_size = 400;
205   get_malloc_leak_info(&info, &overall_size, &info_size, &total_memory, &backtrace_size);
206   EXPECT_EQ(nullptr, info);
207   EXPECT_EQ(0U, overall_size);
208   EXPECT_EQ(0U, info_size);
209   EXPECT_EQ(0U, total_memory);
210   EXPECT_EQ(0U, backtrace_size);
211 
212   free_malloc_leak_info(info);
213 
214   malloc_enable();
215   malloc_disable();
216 
217   EXPECT_EQ(0, malloc_iterate(0, 0, nullptr, nullptr));
218 
219   // Malloc hooks doesn't support any backtracing.
220   EXPECT_EQ(0, malloc_backtrace(nullptr, nullptr, 10));
221 }
222 
TEST_F(MallocHooksTest,malloc_hook)223 TEST_F(MallocHooksTest, malloc_hook) {
224   RunTest("*.DISABLED_malloc_hook");
225 }
226 
TEST_F(MallocHooksTest,DISABLED_malloc_hook)227 TEST_F(MallocHooksTest, DISABLED_malloc_hook) {
228   Init();
229   ASSERT_TRUE(__malloc_hook != nullptr);
230   __malloc_hook = test_malloc_hook;
231 
232   void* ptr = malloc(1024);
233   ASSERT_TRUE(ptr != nullptr);
234   write(0, ptr, 0);
235   free(ptr);
236 
237   EXPECT_TRUE(malloc_hook_called_) << "The malloc hook was not called.";
238   EXPECT_TRUE(void_arg_ != nullptr) << "The malloc hook was called with a nullptr.";
239 }
240 
TEST_F(MallocHooksTest,free_hook)241 TEST_F(MallocHooksTest, free_hook) {
242   RunTest("*.DISABLED_free_hook");
243 }
244 
TEST_F(MallocHooksTest,DISABLED_free_hook)245 TEST_F(MallocHooksTest, DISABLED_free_hook) {
246   Init();
247   ASSERT_TRUE(__free_hook != nullptr);
248   __free_hook = test_free_hook;
249 
250   void* ptr = malloc(1024);
251   ASSERT_TRUE(ptr != nullptr);
252   free(ptr);
253   write(0, ptr, 0);
254 
255   EXPECT_TRUE(free_hook_called_) << "The free hook was not called.";
256   EXPECT_TRUE(void_arg_ != nullptr) << "The free hook was called with a nullptr.";
257 }
258 
TEST_F(MallocHooksTest,realloc_hook)259 TEST_F(MallocHooksTest, realloc_hook) {
260   RunTest("*.DISABLED_realloc_hook");
261 }
262 
TEST_F(MallocHooksTest,DISABLED_realloc_hook)263 TEST_F(MallocHooksTest, DISABLED_realloc_hook) {
264   Init();
265   ASSERT_TRUE(__realloc_hook != nullptr);
266   __realloc_hook = test_realloc_hook;
267 
268   void* ptr = malloc(1024);
269   ASSERT_TRUE(ptr != nullptr);
270   ptr = realloc(ptr, 2048);
271   free(ptr);
272   write(0, ptr, 0);
273 
274   EXPECT_TRUE(realloc_hook_called_) << "The realloc hook was not called.";
275   EXPECT_TRUE(void_arg_ != nullptr) << "The realloc hook was called with a nullptr.";
276 }
277 
TEST_F(MallocHooksTest,memalign_hook)278 TEST_F(MallocHooksTest, memalign_hook) {
279   RunTest("*.DISABLED_memalign_hook");
280 }
281 
TEST_F(MallocHooksTest,DISABLED_memalign_hook)282 TEST_F(MallocHooksTest, DISABLED_memalign_hook) {
283   Init();
284   ASSERT_TRUE(__memalign_hook != nullptr);
285   __memalign_hook = test_memalign_hook;
286 
287   void* ptr = memalign(32, 1024);
288   ASSERT_TRUE(ptr != nullptr);
289   free(ptr);
290   write(0, ptr, 0);
291 
292   EXPECT_TRUE(memalign_hook_called_) << "The memalign hook was not called.";
293   EXPECT_TRUE(void_arg_ != nullptr) << "The memalign hook was called with a nullptr.";
294 }
295 
TEST_F(MallocHooksTest,posix_memalign_hook)296 TEST_F(MallocHooksTest, posix_memalign_hook) {
297   RunTest("*.DISABLED_posix_memalign_hook");
298 }
299 
TEST_F(MallocHooksTest,DISABLED_posix_memalign_hook)300 TEST_F(MallocHooksTest, DISABLED_posix_memalign_hook) {
301   Init();
302   ASSERT_TRUE(__memalign_hook != nullptr);
303   __memalign_hook = test_memalign_hook;
304 
305   void* ptr;
306   ASSERT_EQ(0, posix_memalign(&ptr, 32, 1024));
307   ASSERT_TRUE(ptr != nullptr);
308   free(ptr);
309   write(0, ptr, 0);
310 
311   EXPECT_TRUE(memalign_hook_called_) << "The memalign hook was not called when running posix_memalign.";
312   EXPECT_TRUE(void_arg_ != nullptr) << "The memalign hook was called with a nullptr.";
313 }
314 
TEST_F(MallocHooksTest,posix_memalign_hook_error)315 TEST_F(MallocHooksTest, posix_memalign_hook_error) {
316   RunTest("*.DISABLED_posix_memalign_hook_error");
317 }
318 
TEST_F(MallocHooksTest,DISABLED_posix_memalign_hook_error)319 TEST_F(MallocHooksTest, DISABLED_posix_memalign_hook_error) {
320   Init();
321   ASSERT_TRUE(__memalign_hook != nullptr);
322   __memalign_hook = test_memalign_hook;
323 
324   void* ptr;
325   ASSERT_EQ(EINVAL, posix_memalign(&ptr, 11, 1024));
326   write(0, ptr, 0);
327 
328   EXPECT_FALSE(memalign_hook_called_)
329       << "The memalign hook was called when running posix_memalign with an error.";
330   EXPECT_FALSE(void_arg_ != nullptr)
331       << "The memalign hook was called with a nullptr with an error.";
332 }
333 
TEST_F(MallocHooksTest,aligned_alloc_hook)334 TEST_F(MallocHooksTest, aligned_alloc_hook) {
335   RunTest("*.DISABLED_aligned_alloc_hook");
336 }
337 
TEST_F(MallocHooksTest,DISABLED_aligned_alloc_hook)338 TEST_F(MallocHooksTest, DISABLED_aligned_alloc_hook) {
339   Init();
340   ASSERT_TRUE(__memalign_hook != nullptr);
341   __memalign_hook = test_memalign_hook;
342 
343   void* ptr = aligned_alloc(32, 1024);
344   ASSERT_TRUE(ptr != nullptr);
345   free(ptr);
346   write(0, ptr, 0);
347 
348   EXPECT_TRUE(memalign_hook_called_) << "The memalign hook was not called when running aligned_alloc.";
349   EXPECT_TRUE(void_arg_ != nullptr) << "The memalign hook was called with a nullptr.";
350 }
351 
TEST_F(MallocHooksTest,aligned_alloc_hook_error)352 TEST_F(MallocHooksTest, aligned_alloc_hook_error) {
353   RunTest("*.DISABLED_aligned_alloc_hook_error");
354 }
355 
TEST_F(MallocHooksTest,DISABLED_aligned_alloc_hook_error)356 TEST_F(MallocHooksTest, DISABLED_aligned_alloc_hook_error) {
357   Init();
358   ASSERT_TRUE(__memalign_hook != nullptr);
359   __memalign_hook = test_memalign_hook;
360 
361   void* ptr = aligned_alloc(11, 1024);
362   ASSERT_TRUE(ptr == nullptr);
363   EXPECT_EQ(EINVAL, errno);
364   write(0, ptr, 0);
365 
366   EXPECT_FALSE(memalign_hook_called_)
367       << "The memalign hook was called when running aligned_alloc with an error.";
368   EXPECT_FALSE(void_arg_ != nullptr)
369       << "The memalign hook was called with a nullptr with an error.";
370 }
371 
372 #if !defined(__LP64__)
TEST_F(MallocHooksTest,pvalloc_hook)373 TEST_F(MallocHooksTest, pvalloc_hook) {
374   RunTest("*.DISABLED_pvalloc_hook");
375 }
376 
377 extern "C" void* pvalloc(size_t);
378 
TEST_F(MallocHooksTest,DISABLED_pvalloc_hook)379 TEST_F(MallocHooksTest, DISABLED_pvalloc_hook) {
380   Init();
381   ASSERT_TRUE(__memalign_hook != nullptr);
382   __memalign_hook = test_memalign_hook;
383 
384   void* ptr = pvalloc(1024);
385   ASSERT_TRUE(ptr != nullptr);
386   write(0, ptr, 0);
387   free(ptr);
388 
389   EXPECT_TRUE(memalign_hook_called_) << "The memalign hook was not called for pvalloc.";
390   EXPECT_TRUE(void_arg_ != nullptr) << "The memalign hook was called with a nullptr.";
391 }
392 
TEST_F(MallocHooksTest,valloc_hook)393 TEST_F(MallocHooksTest, valloc_hook) {
394   RunTest("*.DISABLED_valloc_hook");
395 }
396 
397 extern "C" void* valloc(size_t);
398 
TEST_F(MallocHooksTest,DISABLED_valloc_hook)399 TEST_F(MallocHooksTest, DISABLED_valloc_hook) {
400   Init();
401   ASSERT_TRUE(__memalign_hook != nullptr);
402   __memalign_hook = test_memalign_hook;
403 
404   void* ptr = valloc(1024);
405   ASSERT_TRUE(ptr != nullptr);
406   write(0, ptr, 0);
407   free(ptr);
408 
409   EXPECT_TRUE(memalign_hook_called_) << "The memalign hook was not called for valloc.";
410   EXPECT_TRUE(void_arg_ != nullptr) << "The memalign hook was called with a nullptr.";
411 }
412 #endif
413