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 <stdint.h> 38#include <stdio.h> 39#include <stdlib.h> 40#include <unistd.h> 41 42#include <new> 43 44 45/* This file defines overrides for the standard allocation functions that allow 46 * a given allocation to be made to fail for testing. If the program is run 47 * with MALLOC_NUMBER_TO_FAIL set to a base-10 number then that allocation will 48 * return NULL. If MALLOC_ABORT_ON_FAIL is also defined then the allocation 49 * will abort() rather than return NULL. 50 * 51 * This code is not thread safe. */ 52 53static uint64_t current_malloc_count = 0; 54static uint64_t malloc_number_to_fail = 0; 55static char failure_enabled = 0, abort_on_fail = 0; 56static int in_call = 0; 57 58extern "C" { 59/* These are other names for the standard allocation functions. */ 60extern void *__libc_malloc(size_t size); 61extern void *__libc_calloc(size_t num_elems, size_t size); 62extern void *__libc_realloc(void *ptr, size_t size); 63} 64 65static void exit_handler(void) { 66 if (failure_enabled && current_malloc_count > malloc_number_to_fail) { 67 _exit(88); 68 } 69} 70 71static void cpp_new_handler() { 72 // Return to try again. It won't fail a second time. 73 return; 74} 75 76/* should_fail_allocation returns true if the current allocation should fail. */ 77static int should_fail_allocation() { 78 static int init = 0; 79 char should_fail; 80 81 if (in_call) { 82 return 0; 83 } 84 85 in_call = 1; 86 87 if (!init) { 88 const char *env = getenv("MALLOC_NUMBER_TO_FAIL"); 89 if (env != NULL && env[0] != 0) { 90 char *endptr; 91 malloc_number_to_fail = strtoull(env, &endptr, 10); 92 if (*endptr == 0) { 93 failure_enabled = 1; 94 atexit(exit_handler); 95 std::set_new_handler(cpp_new_handler); 96 } 97 } 98 abort_on_fail = (NULL != getenv("MALLOC_ABORT_ON_FAIL")); 99 init = 1; 100 } 101 102 in_call = 0; 103 104 if (!failure_enabled) { 105 return 0; 106 } 107 108 should_fail = (current_malloc_count == malloc_number_to_fail); 109 current_malloc_count++; 110 111 if (should_fail && abort_on_fail) { 112 abort(); 113 } 114 return should_fail; 115} 116 117extern "C" { 118 119void *malloc(size_t size) { 120 if (should_fail_allocation()) { 121 return NULL; 122 } 123 124 return __libc_malloc(size); 125} 126 127void *calloc(size_t num_elems, size_t size) { 128 if (should_fail_allocation()) { 129 return NULL; 130 } 131 132 return __libc_calloc(num_elems, size); 133} 134 135void *realloc(void *ptr, size_t size) { 136 if (should_fail_allocation()) { 137 return NULL; 138 } 139 140 return __libc_realloc(ptr, size); 141} 142 143} // extern "C" 144 145#endif /* defined(linux) && GLIBC && !ARM && !AARCH64 && !ASAN */ 146