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