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(__has_feature) 18 #if __has_feature(address_sanitizer) || __has_feature(memory_sanitizer) 19 #define OPENSSL_ASAN 20 #endif 21 #endif 22 23 #if defined(__GLIBC__) && !defined(__UCLIBC__) 24 #define OPENSSL_GLIBC 25 #endif 26 27 // This file isn't built on ARM or Aarch64 because we link statically in those 28 // builds and trying to override malloc in a static link doesn't work. It also 29 // requires glibc. It's also disabled on ASan builds as this interferes with 30 // ASan's malloc interceptor. 31 // 32 // TODO(davidben): See if this and ASan's and MSan's interceptors can be made to 33 // coexist. 34 #if defined(__linux__) && defined(OPENSSL_GLIBC) && !defined(OPENSSL_ARM) && \ 35 !defined(OPENSSL_AARCH64) && !defined(OPENSSL_ASAN) 36 37 #include <errno.h> 38 #include <signal.h> 39 #include <stdint.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <unistd.h> 43 44 #include <new> 45 46 47 /* This file defines overrides for the standard allocation functions that allow 48 * a given allocation to be made to fail for testing. If the program is run 49 * with MALLOC_NUMBER_TO_FAIL set to a base-10 number then that allocation will 50 * return NULL. If MALLOC_BREAK_ON_FAIL is also defined then the allocation 51 * will signal SIGTRAP rather than return NULL. 52 * 53 * This code is not thread safe. */ 54 55 static uint64_t current_malloc_count = 0; 56 static uint64_t malloc_number_to_fail = 0; 57 static char failure_enabled = 0, break_on_fail = 0; 58 static int in_call = 0; 59 60 extern "C" { 61 /* These are other names for the standard allocation functions. */ 62 extern void *__libc_malloc(size_t size); 63 extern void *__libc_calloc(size_t num_elems, size_t size); 64 extern void *__libc_realloc(void *ptr, size_t size); 65 } 66 67 static void exit_handler(void) { 68 if (failure_enabled && current_malloc_count > malloc_number_to_fail) { 69 _exit(88); 70 } 71 } 72 73 static void cpp_new_handler() { 74 // Return to try again. It won't fail a second time. 75 return; 76 } 77 78 /* should_fail_allocation returns true if the current allocation should fail. */ 79 static int should_fail_allocation() { 80 static int init = 0; 81 char should_fail; 82 83 if (in_call) { 84 return 0; 85 } 86 87 in_call = 1; 88 89 if (!init) { 90 const char *env = getenv("MALLOC_NUMBER_TO_FAIL"); 91 if (env != NULL && env[0] != 0) { 92 char *endptr; 93 malloc_number_to_fail = strtoull(env, &endptr, 10); 94 if (*endptr == 0) { 95 failure_enabled = 1; 96 atexit(exit_handler); 97 std::set_new_handler(cpp_new_handler); 98 } 99 } 100 break_on_fail = (NULL != getenv("MALLOC_BREAK_ON_FAIL")); 101 init = 1; 102 } 103 104 in_call = 0; 105 106 if (!failure_enabled) { 107 return 0; 108 } 109 110 should_fail = (current_malloc_count == malloc_number_to_fail); 111 current_malloc_count++; 112 113 if (should_fail && break_on_fail) { 114 raise(SIGTRAP); 115 } 116 return should_fail; 117 } 118 119 extern "C" { 120 121 void *malloc(size_t size) { 122 if (should_fail_allocation()) { 123 errno = ENOMEM; 124 return NULL; 125 } 126 127 return __libc_malloc(size); 128 } 129 130 void *calloc(size_t num_elems, size_t size) { 131 if (should_fail_allocation()) { 132 errno = ENOMEM; 133 return NULL; 134 } 135 136 return __libc_calloc(num_elems, size); 137 } 138 139 void *realloc(void *ptr, size_t size) { 140 if (should_fail_allocation()) { 141 errno = ENOMEM; 142 return NULL; 143 } 144 145 return __libc_realloc(ptr, size); 146 } 147 148 } // extern "C" 149 150 #endif /* defined(linux) && GLIBC && !ARM && !AARCH64 && !ASAN */ 151