diff options
author | Matthijs Kooijman <matthijs@stdin.nl> | 2020-09-17 17:59:08 +0200 |
---|---|---|
committer | Matthijs Kooijman <matthijs@stdin.nl> | 2020-09-17 20:02:03 +0200 |
commit | 1a885ce890219213ac24c00d5aededa88c122fe1 (patch) | |
tree | 3295388161d93c8b8d84fda7950345502ea97a37 | |
parent | 6e0fb1ee25efa07be5aef320501f3908f44e5b79 (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.cpp | 37 |
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 { |