changeset 26732:8f1c468c2ecd

Merge #9856: Terminate immediately when allocation fails d4ee7ba prevector: assert successful allocation (Cory Fields) c5f008a don't throw std::bad_alloc when out of memory. Instead, terminate immediately (Cory Fields) Tree-SHA512: 699ce8df5b1775a99c71d3cfc952b45da1c0091e1a4b6adfac52d5be6144c3d98f88ac3af90e5c73fff2f74666a499feb4a34434683ce5979814e869c0aeddc3
author Wladimir J. van der Laan <laanwj@gmail.com>
date Tue, 28 Feb 2017 11:37:00 +0100
parents 7a3b3bf954ae 05e9c7f7436f
children 52c9888471c9
files
diffstat 2 files changed, 22 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/init.cpp	Mon Feb 27 22:33:40 2017 +0100
+++ b/src/init.cpp	Tue Feb 28 11:37:00 2017 +0100
@@ -797,6 +797,19 @@
 
 }
 
+[[noreturn]] static void new_handler_terminate()
+{
+    // Rather than throwing std::bad-alloc if allocation fails, terminate
+    // immediately to (try to) avoid chain corruption.
+    // Since LogPrintf may itself allocate memory, set the handler directly
+    // to terminate first.
+    std::set_new_handler(std::terminate);
+    LogPrintf("Error: Out of memory. Terminating.\n");
+
+    // The log was successful, terminate now.
+    std::terminate();
+};
+
 bool AppInitBasicSetup()
 {
     // ********************************************************* Step 1: setup
@@ -849,6 +862,9 @@
     // Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly
     signal(SIGPIPE, SIG_IGN);
 #endif
+
+    std::set_new_handler(new_handler_terminate);
+
     return true;
 }
 
--- a/src/prevector.h	Mon Feb 27 22:33:40 2017 +0100
+++ b/src/prevector.h	Tue Feb 28 11:37:00 2017 +0100
@@ -5,6 +5,7 @@
 #ifndef _BITCOIN_PREVECTOR_H_
 #define _BITCOIN_PREVECTOR_H_
 
+#include <assert.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
@@ -170,10 +171,15 @@
             }
         } else {
             if (!is_direct()) {
+                /* FIXME: Because malloc/realloc here won't call new_handler if allocation fails, assert
+                    success. These should instead use an allocator or new/delete so that handlers
+                    are called as necessary, but performance would be slightly degraded by doing so. */
                 _union.indirect = static_cast<char*>(realloc(_union.indirect, ((size_t)sizeof(T)) * new_capacity));
+                assert(_union.indirect);
                 _union.capacity = new_capacity;
             } else {
                 char* new_indirect = static_cast<char*>(malloc(((size_t)sizeof(T)) * new_capacity));
+                assert(new_indirect);
                 T* src = direct_ptr(0);
                 T* dst = reinterpret_cast<T*>(new_indirect);
                 memcpy(dst, src, size() * sizeof(T));