Tag operator new overloads with noexcept

According to the C++ standard, regular operator new must always return a valid pointer, and allocation failure should throw an exception.

The original game did not use exceptions, and instead had its operator new return null on alloc failure.

Clang and GCC seem to be enforcing the standard here, and this is causing crashes on non-Windows platforms like https://sentry.twilitrealm.dev/organizations/twilitrealm/issues/952/, where a JAISe allocation failure (custom pooled operator new overload) crashes the game when it should be handled gracefully. MSVC seems to not make use of this opportunity, meaning the code works as intended.

Tagging the operators with noexcept seems to satisfy GCC, but I admit cppreference is very light on details here.
This commit is contained in:
PJB3005
2026-05-18 02:06:38 +02:00
parent f33827a969
commit 05edbec827
2 changed files with 24 additions and 20 deletions
@@ -287,28 +287,28 @@ template <typename T>
class JASPoolAllocObject {
public:
#if TARGET_PC
static void* operator new(size_t n, JKRHeapToken) {
static void* operator new(size_t n, JKRHeapToken) IF_DUSK(noexcept) {
return operator new(n);
}
#endif
static void* operator new(size_t n) {
static void* operator new(size_t n) IF_DUSK(noexcept) {
#if PLATFORM_GCN
JASMemPool<T>& memPool_ = getMemPool_();
#endif
return memPool_.alloc(n);
}
static void* operator new(size_t n, void* ptr) {
static void* operator new(size_t n, void* ptr) IF_DUSK(noexcept) {
return ptr;
}
#if TARGET_PC
static void operator delete(void* ptr, size_t n, JKRHeapToken) {
static void operator delete(void* ptr, size_t n, JKRHeapToken) IF_DUSK(noexcept) {
operator delete(ptr, n);
}
#endif
static void operator delete(void* ptr, size_t n) {
static void operator delete(void* ptr, size_t n) IF_DUSK(noexcept) {
#if PLATFORM_GCN
JASMemPool<T>& memPool_ = getMemPool_();
#endif
+19 -15
View File
@@ -237,11 +237,11 @@ enum class JKRHeapToken {
Dummy
};
inline void* operator new(size_t, JKRHeapToken, void* where) {
inline void* operator new(size_t, JKRHeapToken, void* where) noexcept {
return where;
}
inline void* operator new[](size_t, JKRHeapToken, void* where) {
inline void* operator new[](size_t, JKRHeapToken, void* where) noexcept {
return where;
}
@@ -264,21 +264,21 @@ inline void* operator new[](size_t, JKRHeapToken, void* where) {
#define JKR_HEAP_TOKEN_PARAM
#endif
void* operator new(size_t size JKR_HEAP_TOKEN_PARAM);
void* operator new(size_t size JKR_HEAP_TOKEN_PARAM, int alignment);
void* operator new(size_t size JKR_HEAP_TOKEN_PARAM, JKRHeap* heap, int alignment);
void* operator new(size_t size JKR_HEAP_TOKEN_PARAM) IF_DUSK(noexcept);
void* operator new(size_t size JKR_HEAP_TOKEN_PARAM, int alignment) IF_DUSK(noexcept);
void* operator new(size_t size JKR_HEAP_TOKEN_PARAM, JKRHeap* heap, int alignment) IF_DUSK(noexcept);
// On PC, these new[] overloads are only used to catch usages of JKR_NEW with [].
void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM);
void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM, int alignment);
void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM, JKRHeap* heap, int alignment);
void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM) IF_DUSK(noexcept);
void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM, int alignment) IF_DUSK(noexcept);
void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM, JKRHeap* heap, int alignment) IF_DUSK(noexcept);
void operator delete(void* ptr JKR_HEAP_TOKEN_PARAM);
void operator delete[](void* ptr JKR_HEAP_TOKEN_PARAM);
void operator delete(void* ptr JKR_HEAP_TOKEN_PARAM) IF_DUSK(noexcept);
void operator delete[](void* ptr JKR_HEAP_TOKEN_PARAM) IF_DUSK(noexcept);
#if TARGET_PC
template<typename T>
void jkrDelete(T* ptr) {
void jkrDelete(T* ptr) IF_DUSK(noexcept) {
if (ptr == nullptr) {
return;
}
@@ -298,7 +298,7 @@ void jkrDelete(T* ptr) {
}
template<>
inline void jkrDelete(void* ptr) {
inline void jkrDelete(void* ptr) IF_DUSK(noexcept) {
if (ptr == nullptr) {
return;
}
@@ -322,7 +322,7 @@ constexpr bool newArgsHasCustomAlignment() {
}
template<typename T, typename... Args>
T* jkrNewArray(size_t count, std::in_place_type_t<T>, Args&&... args) {
T* jkrNewArray(size_t count, std::in_place_type_t<T>, Args&&... args) IF_DUSK(noexcept) {
size_t allocSize = count * sizeof(T);
if constexpr (!std::is_trivially_destructible<T>()) {
static_assert(
@@ -333,6 +333,10 @@ T* jkrNewArray(size_t count, std::in_place_type_t<T>, Args&&... args) {
}
void* ptr = operator new(allocSize, JKRHeapToken::Dummy, args...);
if (!ptr) {
return nullptr;
}
T* dataPtr;
if constexpr (!std::is_trivially_destructible<T>()) {
auto length = static_cast<size_t*>(ptr);
@@ -352,7 +356,7 @@ T* jkrNewArray(size_t count, std::in_place_type_t<T>, Args&&... args) {
}
template<typename T>
void jkrDeleteArray(T* pointer) {
void jkrDeleteArray(T* pointer) IF_DUSK(noexcept) {
if (pointer == nullptr) {
return;
}
@@ -372,7 +376,7 @@ void jkrDeleteArray(T* pointer) {
}
template<>
inline void jkrDeleteArray(void* pointer) {
inline void jkrDeleteArray(void* pointer) IF_DUSK(noexcept) {
if (pointer == nullptr) {
return;
}