Skip to content

Commit 1a885ce

Browse files
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 arduino#287.
1 parent 6e0fb1e commit 1a885ce

File tree

1 file changed

+36
-1
lines changed

1 file changed

+36
-1
lines changed

Diff for: cores/arduino/new.cpp

+36-1
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,61 @@
1818

1919
#include "new.h"
2020

21+
// The C++ spec dicates that allocation failure should cause the
22+
// (non-nothrow version of the) operator new to throw an exception.
23+
// Since we expect to have exceptions disabled, it would be more
24+
// appropriate (and probably standards-compliant) to terminate instead.
25+
// Historically failure causes null to be returned, but this define
26+
// allows switching to more robust terminating behaviour (that might
27+
// become the default at some point in the future). Note that any code
28+
// that wants null to be returned can (and should) use the nothrow
29+
// versions of the new statement anyway and is unaffected by this.
30+
// #define NEW_TERMINATES_ON_FAILURE
31+
2132
namespace std {
33+
// Defined in abi.cpp
34+
void terminate();
35+
2236
const nothrow_t nothrow;
2337
}
2438

25-
void * operator new(size_t size) {
39+
static void * new_helper(size_t size) {
2640
// Even zero-sized allocations should return a unique pointer, but
2741
// malloc does not guarantee this
2842
if (size == 0)
2943
size = 1;
3044
return malloc(size);
3145
}
46+
47+
void * operator new(size_t size) {
48+
void *res = new_helper(size);
49+
#if defined(NEW_TERMINATES_ON_FAILURE)
50+
if (!res)
51+
std::terminate();
52+
#endif
53+
return res;
54+
}
3255
void * operator new[](size_t size) {
3356
return operator new(size);
3457
}
3558

3659
void * operator new(size_t size, const std::nothrow_t tag) noexcept {
60+
#if defined(NEW_TERMINATES_ON_FAILURE)
61+
// Cannot call throwing operator new as standard suggests, so call
62+
// new_helper directly then
63+
return new_helper(size);
64+
#else
3765
return operator new(size);
66+
#endif
3867
}
3968
void * operator new[](size_t size, const std::nothrow_t& tag) noexcept {
69+
#if defined(NEW_TERMINATES_ON_FAILURE)
70+
// Cannot call throwing operator new[] as standard suggests, so call
71+
// malloc directly then
72+
return new_helper(size);
73+
#else
4074
return operator new[](size);
75+
#endif
4176
}
4277

4378
void * operator new(size_t size, void *place) noexcept {

0 commit comments

Comments
 (0)