1 /* Copyright (c) 2014, Google Inc. 2 * 3 * Permission to use, copy, modify, and/or distribute this software for any 4 * purpose with or without fee is hereby granted, provided that the above 5 * copyright notice and this permission notice appear in all copies. 6 * 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 14 15 #include <openssl/base.h> 16 17 #if defined(__GLIBC__) && !defined(__UCLIBC__) 18 #define OPENSSL_GLIBC 19 #endif 20 21 // This file isn't built on ARM or Aarch64 because we link statically in those 22 // builds and trying to override malloc in a static link doesn't work. It also 23 // requires glibc. It's also disabled on ASan builds as this interferes with 24 // ASan's malloc interceptor. 25 // 26 // TODO(davidben): See if this and ASan's and MSan's interceptors can be made to 27 // coexist. 28 #if defined(__linux__) && defined(OPENSSL_GLIBC) && !defined(OPENSSL_ARM) && \ 29 !defined(OPENSSL_AARCH64) && !defined(OPENSSL_ASAN) && \ 30 !defined(OPENSSL_MSAN) 31 32 #include <errno.h> 33 #include <signal.h> 34 #include <stdint.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <unistd.h> 38 39 #include <new> 40 41 42 // This file defines overrides for the standard allocation functions that allow 43 // a given allocation to be made to fail for testing. If the program is run 44 // with MALLOC_NUMBER_TO_FAIL set to a base-10 number then that allocation will 45 // return NULL. If MALLOC_BREAK_ON_FAIL is also defined then the allocation 46 // will signal SIGTRAP rather than return NULL. 47 // 48 // This code is not thread safe. 49 50 static uint64_t current_malloc_count = 0; 51 static uint64_t malloc_number_to_fail = 0; 52 static bool failure_enabled = false, break_on_fail = false, in_call = false; 53 54 extern "C" { 55 // These are other names for the standard allocation functions. 56 extern void *__libc_malloc(size_t size); 57 extern void *__libc_calloc(size_t num_elems, size_t size); 58 extern void *__libc_realloc(void *ptr, size_t size); 59 } 60 61 static void exit_handler(void) { 62 if (failure_enabled && current_malloc_count > malloc_number_to_fail) { 63 _exit(88); 64 } 65 } 66 67 static void cpp_new_handler() { 68 // Return to try again. It won't fail a second time. 69 return; 70 } 71 72 // should_fail_allocation returns true if the current allocation should fail. 73 static bool should_fail_allocation() { 74 static bool init = false; 75 76 if (in_call) { 77 return false; 78 } 79 80 in_call = true; 81 82 if (!init) { 83 const char *env = getenv("MALLOC_NUMBER_TO_FAIL"); 84 if (env != NULL && env[0] != 0) { 85 char *endptr; 86 malloc_number_to_fail = strtoull(env, &endptr, 10); 87 if (*endptr == 0) { 88 failure_enabled = true; 89 atexit(exit_handler); 90 std::set_new_handler(cpp_new_handler); 91 } 92 } 93 break_on_fail = (NULL != getenv("MALLOC_BREAK_ON_FAIL")); 94 init = true; 95 } 96 97 in_call = false; 98 99 if (!failure_enabled) { 100 return false; 101 } 102 103 bool should_fail = (current_malloc_count == malloc_number_to_fail); 104 current_malloc_count++; 105 106 if (should_fail && break_on_fail) { 107 raise(SIGTRAP); 108 } 109 return should_fail; 110 } 111 112 extern "C" { 113 114 void *malloc(size_t size) { 115 if (should_fail_allocation()) { 116 errno = ENOMEM; 117 return NULL; 118 } 119 120 return __libc_malloc(size); 121 } 122 123 void *calloc(size_t num_elems, size_t size) { 124 if (should_fail_allocation()) { 125 errno = ENOMEM; 126 return NULL; 127 } 128 129 return __libc_calloc(num_elems, size); 130 } 131 132 void *realloc(void *ptr, size_t size) { 133 if (should_fail_allocation()) { 134 errno = ENOMEM; 135 return NULL; 136 } 137 138 return __libc_realloc(ptr, size); 139 } 140 141 } // extern "C" 142 143 #endif // defined(linux) && GLIBC && !ARM && !AARCH64 && !ASAN 144