This is mostly the same a cpp_alloc in tcmalloc.cc. TODO(csilvers): change Allocate() above to call cpp_alloc, so we don't have to reproduce the logic here. To make tc_new_mode work properly, I think we'll need to separate out the logic of throwing from the logic of calling the new-handler.
| 1104 | // properly, I think we'll need to separate out the logic of throwing |
| 1105 | // from the logic of calling the new-handler. |
| 1106 | inline void* debug_cpp_alloc(size_t size, int new_type, bool nothrow) { |
| 1107 | for (;;) { |
| 1108 | void* p = DebugAllocate(size, new_type); |
| 1109 | #ifdef PREANSINEW |
| 1110 | return p; |
| 1111 | #else |
| 1112 | if (p == NULL) { // allocation failed |
| 1113 | // Get the current new handler. NB: this function is not |
| 1114 | // thread-safe. We make a feeble stab at making it so here, but |
| 1115 | // this lock only protects against tcmalloc interfering with |
| 1116 | // itself, not with other libraries calling set_new_handler. |
| 1117 | std::new_handler nh; |
| 1118 | { |
| 1119 | SpinLockHolder h(&set_new_handler_lock); |
| 1120 | nh = std::set_new_handler(0); |
| 1121 | (void) std::set_new_handler(nh); |
| 1122 | } |
| 1123 | #if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) |
| 1124 | if (nh) { |
| 1125 | // Since exceptions are disabled, we don't really know if new_handler |
| 1126 | // failed. Assume it will abort if it fails. |
| 1127 | (*nh)(); |
| 1128 | continue; |
| 1129 | } |
| 1130 | return 0; |
| 1131 | #else |
| 1132 | // If no new_handler is established, the allocation failed. |
| 1133 | if (!nh) { |
| 1134 | if (nothrow) return 0; |
| 1135 | throw std::bad_alloc(); |
| 1136 | } |
| 1137 | // Otherwise, try the new_handler. If it returns, retry the |
| 1138 | // allocation. If it throws std::bad_alloc, fail the allocation. |
| 1139 | // if it throws something else, don't interfere. |
| 1140 | try { |
| 1141 | (*nh)(); |
| 1142 | } catch (const std::bad_alloc&) { |
| 1143 | if (!nothrow) throw; |
| 1144 | return p; |
| 1145 | } |
| 1146 | #endif // (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) |
| 1147 | } else { // allocation success |
| 1148 | return p; |
| 1149 | } |
| 1150 | #endif // PREANSINEW |
| 1151 | } |
| 1152 | } |
| 1153 | |
| 1154 | inline void* do_debug_malloc_or_debug_cpp_alloc(size_t size) { |
| 1155 | return tc_new_mode ? debug_cpp_alloc(size, MallocBlock::kMallocType, true) |
no test coverage detected