From 5491e0cdcc02916d44ca1f43eab8919d28e4406c Mon Sep 17 00:00:00 2001 From: Daniel Bertalan Date: Sun, 20 Jun 2021 09:39:20 +0200 Subject: AK+Kernel: Make fallible allocations compiler-agnostic In standard C++, operators `new` and `new[]` are guaranteed to return a valid (non-null) pointer and throw an exception if the allocation couldn't be performed. Based on this, compilers did not check the returned pointer before attempting to use them for object construction. To avoid this, the allocator operators were changed to be `noexcept` in PR #7026, which made GCC emit the desired null checks. Unfortunately, this is a non-standard feature which meant that Clang would not accept these function definitions, as it did not match its expected declaration. To make compiling using Clang possible, the special "nothrow" versions of `new` are implemented in this commit. These take a tag type of `std::nothrow_t` (used for disambiguating from placement new/etc.), and are allowed by the standard to return null. There is a global variable, `std::nothrow`, declared with this type, which is also exported into the global namespace. To perform fallible allocations, the following syntax should be used: ```cpp auto ptr = new (nothrow) T; ``` As we don't support exceptions in the kernel, the only way of uphold the "throwing" new's guarantee is to abort if the allocation couldn't be performed. Once we have proper OOM handling in the kernel, this should only be used for critical allocations, where we wouldn't be able to recover from allocation failures anyway. --- AK/kmalloc.h | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'AK') diff --git a/AK/kmalloc.h b/AK/kmalloc.h index ad12854cbc..5807828980 100644 --- a/AK/kmalloc.h +++ b/AK/kmalloc.h @@ -41,34 +41,49 @@ inline size_t malloc_good_size(size_t size) { return size; } # ifdef __serenity__ +# include # include inline void* operator new(size_t size) +{ + void* ptr = kmalloc(size); + VERIFY(ptr); + return ptr; +} + +inline void* operator new(size_t size, const std::nothrow_t&) noexcept { return kmalloc(size); } -inline void operator delete(void* ptr) +inline void operator delete(void* ptr) noexcept { return kfree(ptr); } -inline void operator delete(void* ptr, size_t) +inline void operator delete(void* ptr, size_t) noexcept { return kfree(ptr); } inline void* operator new[](size_t size) +{ + void* ptr = kmalloc(size); + VERIFY(ptr); + return ptr; +} + +inline void* operator new[](size_t size, const std::nothrow_t&) noexcept { return kmalloc(size); } -inline void operator delete[](void* ptr) +inline void operator delete[](void* ptr) noexcept { return kfree(ptr); } -inline void operator delete[](void* ptr, size_t) +inline void operator delete[](void* ptr, size_t) noexcept { return kfree(ptr); } @@ -76,3 +91,5 @@ inline void operator delete[](void* ptr, size_t) # endif #endif + +using std::nothrow; -- cgit v1.2.3