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 46void get_malloc_leak_info(uint8_t**, size_t*, size_t*, size_t*, size_t*); 47void free_malloc_leak_info(uint8_t*); 48int malloc_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*); 49void malloc_enable(); 50void malloc_disable(); 51ssize_t malloc_backtrace(void*, uintptr_t*, size_t); 52 53__END_DECLS 54 55class MallocHooksTest : public ::testing::Test { 56 protected: 57 void SetUp() override { 58 ASSERT_EQ(0, setenv("LIBC_HOOKS_ENABLE", "1", true)); 59 initialized_ = false; 60 } 61 62 void TearDown() override { 63 if (initialized_) { 64 Reset(); 65 } 66 ASSERT_EQ(0, unsetenv("LIBC_HOOKS_ENABLE")); 67 } 68 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 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 118bool MallocHooksTest::malloc_hook_called_; 119bool MallocHooksTest::free_hook_called_; 120bool MallocHooksTest::realloc_hook_called_; 121bool MallocHooksTest::memalign_hook_called_; 122const void* MallocHooksTest::void_arg_; 123 124void* (*MallocHooksTest::orig_malloc_hook_)(size_t, const void*); 125void (*MallocHooksTest::orig_free_hook_)(void*, const void*); 126void* (*MallocHooksTest::orig_realloc_hook_)(void*, size_t, const void*); 127void* (*MallocHooksTest::orig_memalign_hook_)(size_t, size_t, const void*); 128 129static 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 136void 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 155void* 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 161void* 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 167void* 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 173void 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 179TEST_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. 184TEST_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 195TEST_F(MallocHooksTest, extended_functions) { 196 RunTest("*.DISABLED_extended_functions"); 197} 198 199TEST_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 223TEST_F(MallocHooksTest, malloc_hook) { 224 RunTest("*.DISABLED_malloc_hook"); 225} 226 227TEST_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 241TEST_F(MallocHooksTest, free_hook) { 242 RunTest("*.DISABLED_free_hook"); 243} 244 245TEST_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 259TEST_F(MallocHooksTest, realloc_hook) { 260 RunTest("*.DISABLED_realloc_hook"); 261} 262 263TEST_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 278TEST_F(MallocHooksTest, memalign_hook) { 279 RunTest("*.DISABLED_memalign_hook"); 280} 281 282TEST_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 296TEST_F(MallocHooksTest, posix_memalign_hook) { 297 RunTest("*.DISABLED_posix_memalign_hook"); 298} 299 300TEST_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 315TEST_F(MallocHooksTest, posix_memalign_hook_error) { 316 RunTest("*.DISABLED_posix_memalign_hook_error"); 317} 318 319TEST_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 334TEST_F(MallocHooksTest, aligned_alloc_hook) { 335 RunTest("*.DISABLED_aligned_alloc_hook"); 336} 337 338TEST_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 352TEST_F(MallocHooksTest, aligned_alloc_hook_error) { 353 RunTest("*.DISABLED_aligned_alloc_hook_error"); 354} 355 356TEST_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__) 373TEST_F(MallocHooksTest, pvalloc_hook) { 374 RunTest("*.DISABLED_pvalloc_hook"); 375} 376 377extern "C" void* pvalloc(size_t); 378 379TEST_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 393TEST_F(MallocHooksTest, valloc_hook) { 394 RunTest("*.DISABLED_valloc_hook"); 395} 396 397extern "C" void* valloc(size_t); 398 399TEST_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