From 9a02bd8043c41f6ee57f136083ffc8bf8ec2bdc9 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 17 Sep 2020 19:29:31 +0200 Subject: Swap new and new.h header files Originally, the Arduino core used "new.h", rather than the standard "new", probably because the implementation was incomplete, and for the most commonly used new and delete operators, no include is needed at all (they are defined implicitly by the compiler). However, now Arduino does expose the "new" name, as an alias for the older "new.h". Given that the standard name is "new", it makes more sense to put the actual content in "new", and make "new.h" a compatibility header that includes "new" instead of the other way around. --- cores/arduino/new | 32 +++++++++++++++++++++++++++++--- cores/arduino/new.h | 34 +++------------------------------- 2 files changed, 32 insertions(+), 34 deletions(-) (limited to 'cores') diff --git a/cores/arduino/new b/cores/arduino/new index aa8ecb5..763f5cc 100644 --- a/cores/arduino/new +++ b/cores/arduino/new @@ -1,5 +1,31 @@ /* -this header is for compatibility with standard c++ header names -so that #include works as expected + Copyright (c) 2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "new.h" + +#ifndef NEW_H +#define NEW_H + +#include + +void * operator new(size_t size); +void * operator new[](size_t size); +void * operator new(size_t size, void * ptr) noexcept; +void operator delete(void * ptr); +void operator delete[](void * ptr); + +#endif + diff --git a/cores/arduino/new.h b/cores/arduino/new.h index 763f5cc..d529853 100644 --- a/cores/arduino/new.h +++ b/cores/arduino/new.h @@ -1,31 +1,3 @@ -/* - Copyright (c) 2014 Arduino. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef NEW_H -#define NEW_H - -#include - -void * operator new(size_t size); -void * operator new[](size_t size); -void * operator new(size_t size, void * ptr) noexcept; -void operator delete(void * ptr); -void operator delete[](void * ptr); - -#endif - +// This file originally used a non-standard name for this Arduino core +// only, so still expose the old new.h name for compatibility. +#include "new" -- cgit v1.2.3-18-g5258 From 07b6bd188f2395551fbd5eee3c3ca7ca3769bbbc Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 17 Sep 2020 17:15:42 +0200 Subject: Clean up and complete `` header This makes this header complete up to including C++14, except two exception classes that cannot be defined without ``. The functions related to the "new_handler" are declared but not actually defined, to prevent overhead and complexity. They are still declared to allow implementing them in user code if needed. This makes the implementation of all operator new and delete functions comply with the C++11/C++14 specification in terms of which should be actually implemented and which should be delegate to other functions. There are still some areas where these implementations are not entirely standards-compliant, which will be fixed in subsequent commits. This fixes part of #287 and fixes #47. --- cores/arduino/new | 35 ++++++++++++++++++++++++++++--- cores/arduino/new.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 79 insertions(+), 13 deletions(-) (limited to 'cores') diff --git a/cores/arduino/new b/cores/arduino/new index 763f5cc..3599571 100644 --- a/cores/arduino/new +++ b/cores/arduino/new @@ -21,11 +21,40 @@ #include +namespace std { + struct nothrow_t {}; + extern const nothrow_t nothrow; + + // These are not actually implemented, to prevent overhead and + // complexity. They are still declared to allow implementing + // them in user code if needed. + typedef void (*new_handler)(); + new_handler set_new_handler(new_handler new_p) noexcept; + new_handler get_new_handler() noexcept; +} // namespace std + void * operator new(size_t size); void * operator new[](size_t size); -void * operator new(size_t size, void * ptr) noexcept; -void operator delete(void * ptr); -void operator delete[](void * ptr); + +void * operator new(size_t size, const std::nothrow_t tag) noexcept; +void * operator new[](size_t size, const std::nothrow_t& tag) noexcept; + +void * operator new(size_t size, void *place) noexcept; +void * operator new[](size_t size, void *place) noexcept; + +void operator delete(void * ptr) noexcept; +void operator delete[](void * ptr) noexcept; + +#if __cplusplus >= 201402L +void operator delete(void* ptr, size_t size) noexcept; +void operator delete[](void * ptr, size_t size) noexcept; +#endif // __cplusplus >= 201402L + +void operator delete(void* ptr, const std::nothrow_t& tag) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& tag) noexcept; + +void operator delete(void* ptr, void* place) noexcept; +void operator delete[](void* ptr, void* place) noexcept; #endif diff --git a/cores/arduino/new.cpp b/cores/arduino/new.cpp index fc30cf8..a36fd21 100644 --- a/cores/arduino/new.cpp +++ b/cores/arduino/new.cpp @@ -16,26 +16,63 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#include "new.h" -void *operator new(size_t size) { - return malloc(size); +namespace std { + const nothrow_t nothrow; } -void *operator new[](size_t size) { +void * operator new(size_t size) { return malloc(size); } +void * operator new[](size_t size) { + return operator new(size); +} -void * operator new(size_t size, void * ptr) noexcept { - (void)size; - return ptr; +void * operator new(size_t size, const std::nothrow_t tag) noexcept { + return operator new(size); +} +void * operator new[](size_t size, const std::nothrow_t& tag) noexcept { + return operator new[](size); } -void operator delete(void * ptr) { - free(ptr); +void * operator new(size_t size, void *place) noexcept { + // Nothing to do + (void)size; // unused + return place; +} +void * operator new[](size_t size, void *place) noexcept { + return operator new(size, place); } -void operator delete[](void * ptr) { +void operator delete(void * ptr) noexcept { free(ptr); } +void operator delete[](void * ptr) noexcept { + operator delete(ptr); +} + +#if __cplusplus >= 201402L +void operator delete(void* ptr, size_t size) noexcept { + operator delete(ptr); +} +void operator delete[](void * ptr, size_t size) noexcept { + operator delete[](ptr); +} +#endif // __cplusplus >= 201402L +void operator delete(void* ptr, const std::nothrow_t& tag) noexcept { + operator delete(ptr); +} +void operator delete[](void* ptr, const std::nothrow_t& tag) noexcept { + operator delete[](ptr); +} + +void operator delete(void* ptr, void* place) noexcept { + (void)ptr; (void)place; // unused + // Nothing to do +} +void operator delete[](void* ptr, void* place) noexcept { + (void)ptr; (void)place; // unused + // Nothing to do +} -- cgit v1.2.3-18-g5258 From 4e469e0c83799ad6d3698e7cfa51ef8a5f2a2c76 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 17 Sep 2020 17:22:41 +0200 Subject: Allow overriding selected operator new and delete functions This makes these functions weak, so that a sketch or library can replace them. This does not apply to all of these operators, only for the ones that the C++ standard specifies as replaceable. --- cores/arduino/new | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'cores') diff --git a/cores/arduino/new b/cores/arduino/new index 3599571..fb60927 100644 --- a/cores/arduino/new +++ b/cores/arduino/new @@ -33,25 +33,25 @@ namespace std { new_handler get_new_handler() noexcept; } // namespace std -void * operator new(size_t size); -void * operator new[](size_t size); +[[gnu::weak]] void * operator new(size_t size); +[[gnu::weak]] void * operator new[](size_t size); -void * operator new(size_t size, const std::nothrow_t tag) noexcept; -void * operator new[](size_t size, const std::nothrow_t& tag) noexcept; +[[gnu::weak]] void * operator new(size_t size, const std::nothrow_t tag) noexcept; +[[gnu::weak]] void * operator new[](size_t size, const std::nothrow_t& tag) noexcept; void * operator new(size_t size, void *place) noexcept; void * operator new[](size_t size, void *place) noexcept; -void operator delete(void * ptr) noexcept; -void operator delete[](void * ptr) noexcept; +[[gnu::weak]] void operator delete(void * ptr) noexcept; +[[gnu::weak]] void operator delete[](void * ptr) noexcept; #if __cplusplus >= 201402L -void operator delete(void* ptr, size_t size) noexcept; -void operator delete[](void * ptr, size_t size) noexcept; +[[gnu::weak]] void operator delete(void* ptr, size_t size) noexcept; +[[gnu::weak]] void operator delete[](void * ptr, size_t size) noexcept; #endif // __cplusplus >= 201402L -void operator delete(void* ptr, const std::nothrow_t& tag) noexcept; -void operator delete[](void* ptr, const std::nothrow_t& tag) noexcept; +[[gnu::weak]] void operator delete(void* ptr, const std::nothrow_t& tag) noexcept; +[[gnu::weak]] void operator delete[](void* ptr, const std::nothrow_t& tag) noexcept; void operator delete(void* ptr, void* place) noexcept; void operator delete[](void* ptr, void* place) noexcept; -- cgit v1.2.3-18-g5258 From b8c6c850421d0d81bb5ea9c340c4fcd958937165 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 17 Sep 2020 17:37:53 +0200 Subject: Add weak `std::terminate()` implementation This allows calling it from other places later. The default implementation calls `abort()`, but making it weak allows user code to override this function (either directly, or by including a library like uclibc++ that implements `std::set_terminate()`). Note that this does not add a declaration for this function, since the standard dictates this to be in ``, but we cannot meaningfully or completely implement that header, so better leave it to be overridden by e.g. libraries like uclibc++. --- cores/arduino/abi.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'cores') diff --git a/cores/arduino/abi.cpp b/cores/arduino/abi.cpp index 8d719b8..b8f76cf 100644 --- a/cores/arduino/abi.cpp +++ b/cores/arduino/abi.cpp @@ -21,6 +21,12 @@ extern "C" void __cxa_pure_virtual(void) __attribute__ ((__noreturn__)); extern "C" void __cxa_deleted_virtual(void) __attribute__ ((__noreturn__)); +namespace std { + [[gnu::weak, noreturn]] void terminate() { + abort(); + } +} + void __cxa_pure_virtual(void) { // We might want to write some diagnostics to uart in this case //std::terminate(); -- cgit v1.2.3-18-g5258 From 66d06b033c3f6eafde901418be3c089ffcc6ebfc Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 17 Sep 2020 17:40:02 +0200 Subject: Call std::terminate on pure or deleted virtual functions These are special functions that are presumably put into vtables for deleted or pure virtual functions. Previously, this would call `abort()` directly, but calling `std::terminate()` achieves the same effect, but allows user code to change the behavior (e.g. to print to serial, blink leds or whatever makes sense). --- cores/arduino/abi.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'cores') diff --git a/cores/arduino/abi.cpp b/cores/arduino/abi.cpp index b8f76cf..6e1b0f8 100644 --- a/cores/arduino/abi.cpp +++ b/cores/arduino/abi.cpp @@ -28,14 +28,9 @@ namespace std { } void __cxa_pure_virtual(void) { - // We might want to write some diagnostics to uart in this case - //std::terminate(); - abort(); + std::terminate(); } void __cxa_deleted_virtual(void) { - // We might want to write some diagnostics to uart in this case - //std::terminate(); - abort(); + std::terminate(); } - -- cgit v1.2.3-18-g5258 From 6e0fb1ee25efa07be5aef320501f3908f44e5b79 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 17 Sep 2020 17:55:27 +0200 Subject: Make zero-sized new standards-compliant This fixes part of #287. --- cores/arduino/new.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'cores') diff --git a/cores/arduino/new.cpp b/cores/arduino/new.cpp index a36fd21..1683594 100644 --- a/cores/arduino/new.cpp +++ b/cores/arduino/new.cpp @@ -23,6 +23,10 @@ namespace std { } void * operator new(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) { -- cgit v1.2.3-18-g5258 From 1a885ce890219213ac24c00d5aededa88c122fe1 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 17 Sep 2020 17:59:08 +0200 Subject: 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. --- cores/arduino/new.cpp | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'cores') 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 { -- cgit v1.2.3-18-g5258 From 6d292502e138b5c73705f0df8095ded3f1df956f Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 17 Sep 2020 19:43:09 +0200 Subject: Use std::size_t in new/delete The standard dictates that `std::size_t` is used, rather than the plain `size_t` type. Even though these types are usually, if not always, exactly the same type, other code might assume that `std::size_t` is actually used and thus also available under that name after including ``. This fixes that by using the right type. One challenge is that it is usually declared in headers that we do not have available, so this just defines the `std::size_t` type in the `` header to work around that. --- cores/arduino/new | 22 ++++++++++++++-------- cores/arduino/new.cpp | 18 +++++++++--------- 2 files changed, 23 insertions(+), 17 deletions(-) (limited to 'cores') diff --git a/cores/arduino/new b/cores/arduino/new index fb60927..8cf2103 100644 --- a/cores/arduino/new +++ b/cores/arduino/new @@ -31,23 +31,29 @@ namespace std { typedef void (*new_handler)(); new_handler set_new_handler(new_handler new_p) noexcept; new_handler get_new_handler() noexcept; + + // This is normally declared in various headers that we do not have + // available, so just define it here. We could also use ::size_t + // below, but then anyone including can no longer assume + // std::size_t is available. + using size_t = ::size_t; } // namespace std -[[gnu::weak]] void * operator new(size_t size); -[[gnu::weak]] void * operator new[](size_t size); +[[gnu::weak]] void * operator new(std::size_t size); +[[gnu::weak]] void * operator new[](std::size_t size); -[[gnu::weak]] void * operator new(size_t size, const std::nothrow_t tag) noexcept; -[[gnu::weak]] void * operator new[](size_t size, const std::nothrow_t& tag) noexcept; +[[gnu::weak]] void * operator new(std::size_t size, const std::nothrow_t tag) noexcept; +[[gnu::weak]] void * operator new[](std::size_t size, const std::nothrow_t& tag) noexcept; -void * operator new(size_t size, void *place) noexcept; -void * operator new[](size_t size, void *place) noexcept; +void * operator new(std::size_t size, void *place) noexcept; +void * operator new[](std::size_t size, void *place) noexcept; [[gnu::weak]] void operator delete(void * ptr) noexcept; [[gnu::weak]] void operator delete[](void * ptr) noexcept; #if __cplusplus >= 201402L -[[gnu::weak]] void operator delete(void* ptr, size_t size) noexcept; -[[gnu::weak]] void operator delete[](void * ptr, size_t size) noexcept; +[[gnu::weak]] void operator delete(void* ptr, std::size_t size) noexcept; +[[gnu::weak]] void operator delete[](void * ptr, std::size_t size) noexcept; #endif // __cplusplus >= 201402L [[gnu::weak]] void operator delete(void* ptr, const std::nothrow_t& tag) noexcept; diff --git a/cores/arduino/new.cpp b/cores/arduino/new.cpp index 19d80b6..9047b2d 100644 --- a/cores/arduino/new.cpp +++ b/cores/arduino/new.cpp @@ -36,7 +36,7 @@ namespace std { const nothrow_t nothrow; } -static void * new_helper(size_t size) { +static void * new_helper(std::size_t size) { // Even zero-sized allocations should return a unique pointer, but // malloc does not guarantee this if (size == 0) @@ -44,7 +44,7 @@ static void * new_helper(size_t size) { return malloc(size); } -void * operator new(size_t size) { +void * operator new(std::size_t size) { void *res = new_helper(size); #if defined(NEW_TERMINATES_ON_FAILURE) if (!res) @@ -52,11 +52,11 @@ void * operator new(size_t size) { #endif return res; } -void * operator new[](size_t size) { +void * operator new[](std::size_t size) { return operator new(size); } -void * operator new(size_t size, const std::nothrow_t tag) noexcept { +void * operator new(std::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 @@ -65,7 +65,7 @@ void * operator new(size_t size, const std::nothrow_t tag) noexcept { return operator new(size); #endif } -void * operator new[](size_t size, const std::nothrow_t& tag) noexcept { +void * operator new[](std::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 @@ -75,12 +75,12 @@ void * operator new[](size_t size, const std::nothrow_t& tag) noexcept { #endif } -void * operator new(size_t size, void *place) noexcept { +void * operator new(std::size_t size, void *place) noexcept { // Nothing to do (void)size; // unused return place; } -void * operator new[](size_t size, void *place) noexcept { +void * operator new[](std::size_t size, void *place) noexcept { return operator new(size, place); } @@ -92,10 +92,10 @@ void operator delete[](void * ptr) noexcept { } #if __cplusplus >= 201402L -void operator delete(void* ptr, size_t size) noexcept { +void operator delete(void* ptr, std::size_t size) noexcept { operator delete(ptr); } -void operator delete[](void * ptr, size_t size) noexcept { +void operator delete[](void * ptr, std::size_t size) noexcept { operator delete[](ptr); } #endif // __cplusplus >= 201402L -- cgit v1.2.3-18-g5258