Skip to content

Commit b1e31af

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 7471928 commit b1e31af

File tree

1 file changed

+38
-1
lines changed

1 file changed

+38
-1
lines changed

Diff for: cores/arduino/new.cpp

+38-1
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,59 @@
1818

1919
#include "new.h"
2020

21-
void * operator new(size_t size) {
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+
32+
namespace std {
33+
// Defined in abi.cpp
34+
void terminate();
35+
}
36+
37+
static void * new_helper(size_t size) {
2238
// Even zero-sized allocations should return a unique pointer, but
2339
// malloc does not guarantee this
2440
if (size == 0)
2541
size = 1;
2642
return malloc(size);
2743
}
44+
45+
void * operator new(size_t size) {
46+
void *res = new_helper(size);
47+
#if defined(NEW_TERMINATES_ON_FAILURE)
48+
if (!res)
49+
std::terminate();
50+
#endif
51+
return res;
52+
}
2853
void * operator new[](size_t size) {
2954
return operator new(size);
3055
}
3156

3257
void * operator new(size_t size, const std::nothrow_t tag) noexcept {
58+
#if defined(NEW_TERMINATES_ON_FAILURE)
59+
// Cannot call throwing operator new as standard suggests, so call
60+
// new_helper directly then
61+
return new_helper(size);
62+
#else
3363
return operator new(size);
64+
#endif
3465
}
3566
void * operator new[](size_t size, const std::nothrow_t& tag) noexcept {
67+
#if defined(NEW_TERMINATES_ON_FAILURE)
68+
// Cannot call throwing operator new[] as standard suggests, so call
69+
// malloc directly then
70+
return new_helper(size);
71+
#else
3672
return operator new[](size);
73+
#endif
3774
}
3875

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

0 commit comments

Comments
 (0)