aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthijs Kooijman <matthijs@stdin.nl>2020-09-17 17:59:08 +0200
committerMatthijs Kooijman <matthijs@stdin.nl>2020-09-17 20:02:03 +0200
commit1a885ce890219213ac24c00d5aededa88c122fe1 (patch)
tree3295388161d93c8b8d84fda7950345502ea97a37
parent6e0fb1ee25efa07be5aef320501f3908f44e5b79 (diff)
Optionally let new terminate on allocation failure
This is currently disabled, keeping the old behavior of returning NULL on failure, but should probably be enabled in the future as code that does want to do a null check has had a chance to switch to the more portable nothrow versions. When enabled, allocation failure calls the weak `std::terminate()`, which calls `abort()` by default, but can be replaced by user code to do more specific handling. To enable this, a macro must be defined (in new.cpp or on the compiler commandline). This fixes part of #287.
-rw-r--r--cores/arduino/new.cpp37
1 files changed, 36 insertions, 1 deletions
diff --git a/cores/arduino/new.cpp b/cores/arduino/new.cpp
index 1683594..19d80b6 100644
--- a/cores/arduino/new.cpp
+++ b/cores/arduino/new.cpp
@@ -18,26 +18,61 @@
#include "new.h"
+// The C++ spec dicates that allocation failure should cause the
+// (non-nothrow version of the) operator new to throw an exception.
+// Since we expect to have exceptions disabled, it would be more
+// appropriate (and probably standards-compliant) to terminate instead.
+// Historically failure causes null to be returned, but this define
+// allows switching to more robust terminating behaviour (that might
+// become the default at some point in the future). Note that any code
+// that wants null to be returned can (and should) use the nothrow
+// versions of the new statement anyway and is unaffected by this.
+// #define NEW_TERMINATES_ON_FAILURE
+
namespace std {
+ // Defined in abi.cpp
+ void terminate();
+
const nothrow_t nothrow;
}
-void * operator new(size_t size) {
+static void * new_helper(size_t size) {
// Even zero-sized allocations should return a unique pointer, but
// malloc does not guarantee this
if (size == 0)
size = 1;
return malloc(size);
}
+
+void * operator new(size_t size) {
+ void *res = new_helper(size);
+#if defined(NEW_TERMINATES_ON_FAILURE)
+ if (!res)
+ std::terminate();
+#endif
+ return res;
+}
void * operator new[](size_t size) {
return operator new(size);
}
void * operator new(size_t size, const std::nothrow_t tag) noexcept {
+#if defined(NEW_TERMINATES_ON_FAILURE)
+ // Cannot call throwing operator new as standard suggests, so call
+ // new_helper directly then
+ return new_helper(size);
+#else
return operator new(size);
+#endif
}
void * operator new[](size_t size, const std::nothrow_t& tag) noexcept {
+#if defined(NEW_TERMINATES_ON_FAILURE)
+ // Cannot call throwing operator new[] as standard suggests, so call
+ // malloc directly then
+ return new_helper(size);
+#else
return operator new[](size);
+#endif
}
void * operator new(size_t size, void *place) noexcept {