• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <errno.h>
30 #include <fcntl.h>
31 #include <poll.h>
32 #include <signal.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <sys/types.h>
36 #include <sys/wait.h>
37 #include <time.h>
38 #include <unistd.h>
39 
40 #include <android-base/stringprintf.h>
41 #include <gtest/gtest.h>
42 #include <log/log.h>
43 
44 #include <string>
45 #include <thread>
46 #include <vector>
47 
48 #include "private/bionic_malloc.h"
49 
50 static constexpr time_t kTimeoutSeconds = 10;
51 
Exec(const char * test_name,const char * debug_options,pid_t * pid,int exit_code=0,time_t timeout_seconds=kTimeoutSeconds)52 static void Exec(const char* test_name, const char* debug_options, pid_t* pid, int exit_code = 0,
53                  time_t timeout_seconds = kTimeoutSeconds) {
54   int fds[2];
55   ASSERT_NE(-1, pipe(fds));
56   ASSERT_NE(-1, fcntl(fds[0], F_SETFL, O_NONBLOCK));
57   if ((*pid = fork()) == 0) {
58     ASSERT_EQ(0, setenv("LIBC_DEBUG_MALLOC_OPTIONS", debug_options, 1));
59     close(fds[0]);
60     close(STDIN_FILENO);
61     close(STDOUT_FILENO);
62     close(STDERR_FILENO);
63     ASSERT_NE(0, dup2(fds[1], STDOUT_FILENO));
64     ASSERT_NE(0, dup2(fds[1], STDERR_FILENO));
65 
66     std::vector<const char*> args;
67     // Get a copy of this argument so it doesn't disappear on us.
68     std::string exec(testing::internal::GetArgvs()[0]);
69     args.push_back(exec.c_str());
70     args.push_back("--gtest_also_run_disabled_tests");
71     std::string filter_arg = std::string("--gtest_filter=") + test_name;
72     args.push_back(filter_arg.c_str());
73     args.push_back(nullptr);
74     execv(args[0], reinterpret_cast<char* const*>(const_cast<char**>(args.data())));
75     exit(20);
76   }
77   ASSERT_NE(-1, *pid);
78   close(fds[1]);
79 
80   std::string output;
81   std::vector<char> buffer(4096);
82   time_t start_time = time(nullptr);
83   bool done = false;
84   while (true) {
85     struct pollfd read_fd = {.fd = fds[0], .events = POLLIN};
86     if (TEMP_FAILURE_RETRY(poll(&read_fd, 1, 1)) > 0) {
87       ssize_t bytes = TEMP_FAILURE_RETRY(read(fds[0], buffer.data(), sizeof(buffer) - 1));
88       if (bytes == -1 && errno == EAGAIN) {
89         continue;
90       }
91       ASSERT_NE(-1, bytes);
92       if (bytes == 0) {
93         done = true;
94         break;
95       }
96       output.append(buffer.data(), bytes);
97     }
98 
99     if ((time(nullptr) - start_time) > timeout_seconds) {
100       kill(*pid, SIGINT);
101       break;
102     }
103   }
104   EXPECT_TRUE(done) << "Timed out while reading data, output:\n" << output;
105 
106   done = false;
107   int status;
108   start_time = time(nullptr);
109   while (true) {
110     int wait_pid = waitpid(*pid, &status, WNOHANG);
111     if (*pid == wait_pid) {
112       done = true;
113       break;
114     }
115     if ((time(nullptr) - start_time) > timeout_seconds) {
116       break;
117     }
118   }
119   if (!done) {
120     kill(*pid, SIGKILL);
121     start_time = time(nullptr);
122     while (true) {
123       int kill_status;
124       int wait_pid = waitpid(*pid, &kill_status, WNOHANG);
125       if (wait_pid == *pid || (time(nullptr) - start_time) > timeout_seconds) {
126         break;
127       }
128     }
129   }
130 
131   ASSERT_TRUE(done) << "Timed out waiting for waitpid, output:\n" << output;
132   ASSERT_FALSE(WIFSIGNALED(status))
133       << "Failed with signal " << WTERMSIG(status) << "\nOutput:\n" << output;
134   ASSERT_EQ(exit_code, WEXITSTATUS(status)) << "Output:\n" << output;
135 }
136 
GetLogStr(pid_t pid,std::string * log_str,log_id log=LOG_ID_MAIN)137 static void GetLogStr(pid_t pid, std::string* log_str, log_id log = LOG_ID_MAIN) {
138   log_str->clear();
139 
140   logger_list* list;
141   list = android_logger_list_open(log, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid);
142   ASSERT_TRUE(list != nullptr);
143 
144   while (true) {
145     log_msg msg;
146     ssize_t actual = android_logger_list_read(list, &msg);
147     if (actual < 0) {
148       if (actual == -EINTR) {
149         // Interrupted retry.
150         continue;
151       } else if (actual == -EAGAIN) {
152         // Non-blocking EOF, finished.
153         break;
154       } else {
155         break;
156       }
157     } else if (actual == 0) {
158       break;
159     }
160     ASSERT_EQ(msg.entry.pid, pid);
161 
162     char* msg_str = msg.msg();
163     if (msg_str != nullptr) {
164       char* tag = msg_str + 1;
165       msg_str = tag + strlen(tag) + 1;
166       *log_str += msg_str;
167       if (log_str->back() != '\n') {
168         *log_str += '\n';
169       }
170     }
171   }
172 
173   android_logger_list_close(list);
174 }
175 
FindStrings(pid_t pid,std::vector<const char * > match_strings,time_t timeout_seconds=kTimeoutSeconds)176 static void FindStrings(pid_t pid, std::vector<const char*> match_strings,
177                         time_t timeout_seconds = kTimeoutSeconds) {
178   std::string log_str;
179   time_t start = time(nullptr);
180   bool found_all;
181   while (true) {
182     GetLogStr(pid, &log_str);
183     found_all = true;
184     for (auto str : match_strings) {
185       if (log_str.find(str) == std::string::npos) {
186         found_all = false;
187         break;
188       }
189     }
190     if (found_all) {
191       return;
192     }
193     if ((time(nullptr) - start) > timeout_seconds) {
194       break;
195     }
196   }
197   ASSERT_TRUE(found_all) << "Didn't find expected log output:\n" + log_str;
198 }
199 
TEST(MallocTests,DISABLED_smoke)200 TEST(MallocTests, DISABLED_smoke) {}
201 
TEST(MallocDebugSystemTest,smoke)202 TEST(MallocDebugSystemTest, smoke) {
203   pid_t pid;
204   ASSERT_NO_FATAL_FAILURE(Exec("MallocTests.DISABLED_smoke", "verbose backtrace", &pid));
205 
206   ASSERT_NO_FATAL_FAILURE(FindStrings(pid, std::vector<const char*>{"malloc debug enabled"}));
207 }
208 
SetAllocationLimit()209 static void SetAllocationLimit() {
210   // Set to a large value, this is only to enable the limit code and
211   // verify that malloc debug is still called properly.
212   size_t limit = 500 * 1024 * 1024;
213   ASSERT_TRUE(android_mallopt(M_SET_ALLOCATION_LIMIT_BYTES, &limit, sizeof(limit)));
214 }
215 
AlignedAlloc()216 static void AlignedAlloc() {
217   void* ptr = aligned_alloc(64, 1152);
218   ASSERT_TRUE(ptr != nullptr);
219   memset(ptr, 0, 1152);
220 }
221 
TEST(MallocTests,DISABLED_leak_memory_aligned_alloc)222 TEST(MallocTests, DISABLED_leak_memory_aligned_alloc) {
223   AlignedAlloc();
224 }
225 
TEST(MallocTests,DISABLED_leak_memory_limit_aligned_alloc)226 TEST(MallocTests, DISABLED_leak_memory_limit_aligned_alloc) {
227   SetAllocationLimit();
228   AlignedAlloc();
229 }
230 
Calloc()231 static void Calloc() {
232   void* ptr = calloc(1, 1123);
233   ASSERT_TRUE(ptr != nullptr);
234   memset(ptr, 1, 1123);
235 }
236 
TEST(MallocTests,DISABLED_leak_memory_calloc)237 TEST(MallocTests, DISABLED_leak_memory_calloc) {
238   Calloc();
239 }
240 
TEST(MallocTests,DISABLED_leak_memory_limit_calloc)241 TEST(MallocTests, DISABLED_leak_memory_limit_calloc) {
242   SetAllocationLimit();
243   Calloc();
244 }
245 
Malloc()246 static void Malloc() {
247   void* ptr = malloc(1123);
248   ASSERT_TRUE(ptr != nullptr);
249   memset(ptr, 0, 1123);
250 }
251 
TEST(MallocTests,DISABLED_leak_memory_malloc)252 TEST(MallocTests, DISABLED_leak_memory_malloc) {
253   Malloc();
254 }
255 
TEST(MallocTests,DISABLED_leak_memory_limit_malloc)256 TEST(MallocTests, DISABLED_leak_memory_limit_malloc) {
257   SetAllocationLimit();
258   Malloc();
259 }
260 
Memalign()261 static void Memalign() {
262   void* ptr = memalign(64, 1123);
263   ASSERT_TRUE(ptr != nullptr);
264   memset(ptr, 0, 1123);
265 }
266 
TEST(MallocTests,DISABLED_leak_memory_memalign)267 TEST(MallocTests, DISABLED_leak_memory_memalign) {
268   Memalign();
269 }
270 
TEST(MallocTests,DISABLED_leak_memory_limit_memalign)271 TEST(MallocTests, DISABLED_leak_memory_limit_memalign) {
272   SetAllocationLimit();
273   Memalign();
274 }
275 
PosixMemalign()276 static void PosixMemalign() {
277   void* ptr;
278   ASSERT_EQ(0, posix_memalign(&ptr, 64, 1123));
279   ASSERT_TRUE(ptr != nullptr);
280   memset(ptr, 0, 1123);
281 }
282 
TEST(MallocTests,DISABLED_leak_memory_posix_memalign)283 TEST(MallocTests, DISABLED_leak_memory_posix_memalign) {
284   PosixMemalign();
285 }
286 
TEST(MallocTests,DISABLED_leak_memory_limit_posix_memalign)287 TEST(MallocTests, DISABLED_leak_memory_limit_posix_memalign) {
288   SetAllocationLimit();
289   PosixMemalign();
290 }
291 
Reallocarray()292 static void Reallocarray() {
293   void* ptr = reallocarray(nullptr, 1, 1123);
294   ASSERT_TRUE(ptr != nullptr);
295   memset(ptr, 0, 1123);
296 }
297 
TEST(MallocTests,DISABLED_leak_memory_reallocarray)298 TEST(MallocTests, DISABLED_leak_memory_reallocarray) {
299   Reallocarray();
300 }
301 
TEST(MallocTests,DISABLED_leak_memory_limit_reallocarray)302 TEST(MallocTests, DISABLED_leak_memory_limit_reallocarray) {
303   SetAllocationLimit();
304   Reallocarray();
305 }
306 
Realloc()307 static void Realloc() {
308   void* ptr = realloc(nullptr, 1123);
309   ASSERT_TRUE(ptr != nullptr);
310   memset(ptr, 0, 1123);
311 }
312 
TEST(MallocTests,DISABLED_leak_memory_realloc)313 TEST(MallocTests, DISABLED_leak_memory_realloc) {
314   Realloc();
315 }
316 
TEST(MallocTests,DISABLED_leak_memory_limit_realloc)317 TEST(MallocTests, DISABLED_leak_memory_limit_realloc) {
318   SetAllocationLimit();
319   Realloc();
320 }
321 
322 #if !defined(__LP64__)
323 extern "C" void* pvalloc(size_t);
324 
Pvalloc()325 static void Pvalloc() {
326   void* ptr = pvalloc(1123);
327   ASSERT_TRUE(ptr != nullptr);
328   memset(ptr, 0, 1123);
329 }
330 
TEST(MallocTests,DISABLED_leak_memory_pvalloc)331 TEST(MallocTests, DISABLED_leak_memory_pvalloc) {
332   Pvalloc();
333 }
334 
TEST(MallocTests,DISABLED_leak_memory_limit_pvalloc)335 TEST(MallocTests, DISABLED_leak_memory_limit_pvalloc) {
336   SetAllocationLimit();
337   Pvalloc();
338 }
339 
340 extern "C" void* valloc(size_t);
341 
Valloc()342 static void Valloc() {
343   void* ptr = valloc(1123);
344   ASSERT_TRUE(ptr != nullptr);
345   memset(ptr, 0, 1123);
346 }
347 
TEST(MallocTests,DISABLED_leak_memory_valloc)348 TEST(MallocTests, DISABLED_leak_memory_valloc) {
349   Valloc();
350 }
351 
TEST(MallocTests,DISABLED_leak_memory_limit_valloc)352 TEST(MallocTests, DISABLED_leak_memory_limit_valloc) {
353   SetAllocationLimit();
354   Valloc();
355 }
356 #endif
357 
VerifyLeak(const char * test_prefix)358 static void VerifyLeak(const char* test_prefix) {
359   struct FunctionInfo {
360     const char* name;
361     size_t size;
362   };
363   static FunctionInfo functions[] = {
364     {
365       "aligned_alloc",
366       1152,
367     },
368     {
369       "calloc",
370       1123,
371     },
372     {
373       "malloc",
374       1123,
375     },
376     {
377       "memalign",
378       1123,
379     },
380     {
381       "posix_memalign",
382       1123,
383     },
384     {
385       "reallocarray",
386       1123,
387     },
388     {
389       "realloc",
390       1123,
391     },
392 #if !defined(__LP64__)
393     {
394       "pvalloc",
395       4096,
396     },
397     {
398       "valloc",
399       1123,
400     }
401 #endif
402   };
403 
404   for (size_t i = 0; i < sizeof(functions) / sizeof(FunctionInfo); i++) {
405     pid_t pid;
406     SCOPED_TRACE(testing::Message() << functions[i].name << " expected size " << functions[i].size);
407     std::string test = std::string("MallocTests.DISABLED_") + test_prefix + functions[i].name;
408     EXPECT_NO_FATAL_FAILURE(Exec(test.c_str(), "verbose backtrace leak_track", &pid));
409 
410     std::string expected_leak = android::base::StringPrintf("leaked block of size %zu at", functions[i].size);
411     EXPECT_NO_FATAL_FAILURE(FindStrings(
412         pid, std::vector<const char*>{"malloc debug enabled", expected_leak.c_str()}));
413   }
414 }
415 
TEST(MallocDebugSystemTest,verify_leak)416 TEST(MallocDebugSystemTest, verify_leak) {
417   VerifyLeak("leak_memory_");
418 }
419 
TEST(MallocDebugSystemTest,verify_leak_allocation_limit)420 TEST(MallocDebugSystemTest, verify_leak_allocation_limit) {
421   VerifyLeak("leak_memory_limit_");
422 }
423 
424 static constexpr int kExpectedExitCode = 30;
425 
TEST(MallocTests,DISABLED_exit_while_threads_allocating)426 TEST(MallocTests, DISABLED_exit_while_threads_allocating) {
427   std::atomic_uint32_t thread_mask;
428   thread_mask = 0;
429 
430   for (size_t i = 0; i < 32; i++) {
431     std::thread malloc_thread([&thread_mask, i] {
432       while (true) {
433         void* ptr = malloc(100);
434         if (ptr == nullptr) {
435           exit(1000);
436         }
437         free(ptr);
438         thread_mask.fetch_or(1 << i);
439       }
440     });
441     malloc_thread.detach();
442   }
443 
444   // Wait until each thread has done at least one allocation.
445   while (thread_mask.load() != 0xffffffff)
446     ;
447   exit(kExpectedExitCode);
448 }
449 
450 // Verify that exiting while other threads are doing malloc operations,
451 // that there are no crashes.
TEST(MallocDebugSystemTest,exit_while_threads_allocating)452 TEST(MallocDebugSystemTest, exit_while_threads_allocating) {
453   for (size_t i = 0; i < 100; i++) {
454     SCOPED_TRACE(::testing::Message() << "Run " << i);
455     pid_t pid;
456     ASSERT_NO_FATAL_FAILURE(Exec("MallocTests.DISABLED_exit_while_threads_allocating",
457                                  "verbose backtrace", &pid, kExpectedExitCode));
458 
459     ASSERT_NO_FATAL_FAILURE(FindStrings(pid, std::vector<const char*>{"malloc debug enabled"}));
460 
461     std::string log_str;
462     GetLogStr(pid, &log_str, LOG_ID_CRASH);
463     ASSERT_TRUE(log_str.find("Fatal signal") == std::string::npos)
464         << "Found crash in log.\nLog message: " << log_str;
465   }
466 }
467