From eb04627741a04209c5ca47b5421f9c8961f58544 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Wed, 1 Jul 2026 14:59:55 -0400
Subject: [PATCH] stdinc: SDL_SetMemoryFunctions now handles NULL function
pointers better.
Now it does _not_ call SDL_SetError(), since that would allocate memory with
the system in a weird state, and setting all four functions to NULL will
restore the original memory functions, as a shortcut vs having to query
SDL_GetOriginalMemoryFunctions() first.
Fixes #15914.
---
include/SDL3/SDL_stdinc.h | 16 +++++++++++-----
src/stdlib/SDL_malloc.c | 25 +++++++++----------------
2 files changed, 20 insertions(+), 21 deletions(-)
diff --git a/include/SDL3/SDL_stdinc.h b/include/SDL3/SDL_stdinc.h
index 88794ce3e32a2..c8ad77e55574e 100644
--- a/include/SDL3/SDL_stdinc.h
+++ b/include/SDL3/SDL_stdinc.h
@@ -1573,12 +1573,18 @@ extern SDL_DECLSPEC void SDLCALL SDL_GetMemoryFunctions(SDL_malloc_func *malloc_
* If used, usually this needs to be the first call made into the SDL library,
* if not the very first thing done at program startup time.
*
+ * It is legal to call this with all 4 parameters set to NULL, which will
+ * restore the original memory functions without having to query them with
+ * SDL_GetOriginalMemoryFunctions() first.
+ *
* \param malloc_func custom malloc function.
* \param calloc_func custom calloc function.
* \param realloc_func custom realloc function.
* \param free_func custom free function.
- * \returns true on success or false on failure; call SDL_GetError() for more
- * information.
+ * \returns true on success or false on failure. This only fails if there is
+ * a mix of NULL and non-NULL parameters. Failure will not set an
+ * error message (which allocates memory) so do _not_ call
+ * SDL_GetError() in response to a failure here.
*
* \threadsafety It is safe to call this function from any thread, but one
* should not replace the memory functions once any allocations
@@ -1590,9 +1596,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_GetMemoryFunctions(SDL_malloc_func *malloc_
* \sa SDL_GetOriginalMemoryFunctions
*/
extern SDL_DECLSPEC bool SDLCALL SDL_SetMemoryFunctions(SDL_malloc_func malloc_func,
- SDL_calloc_func calloc_func,
- SDL_realloc_func realloc_func,
- SDL_free_func free_func);
+ SDL_calloc_func calloc_func,
+ SDL_realloc_func realloc_func,
+ SDL_free_func free_func);
/**
* Allocate memory aligned to a specific alignment.
diff --git a/src/stdlib/SDL_malloc.c b/src/stdlib/SDL_malloc.c
index cd48c61d9faf6..3e7d0fdc9a7ee 100644
--- a/src/stdlib/SDL_malloc.c
+++ b/src/stdlib/SDL_malloc.c
@@ -6537,23 +6537,16 @@ bool SDL_SetMemoryFunctions(SDL_malloc_func malloc_func,
SDL_realloc_func realloc_func,
SDL_free_func free_func)
{
- CHECK_PARAM(!malloc_func) {
- return SDL_InvalidParamError("malloc_func");
- }
- CHECK_PARAM(!calloc_func) {
- return SDL_InvalidParamError("calloc_func");
- }
- CHECK_PARAM(!realloc_func) {
- return SDL_InvalidParamError("realloc_func");
- }
- CHECK_PARAM(!free_func) {
- return SDL_InvalidParamError("free_func");
+ if (!malloc_func && !calloc_func && !realloc_func && !free_func) {
+ SDL_GetOriginalMemoryFunctions(&s_mem.malloc_func, &s_mem.calloc_func, &s_mem.realloc_func, &s_mem.free_func);
+ } else if (!malloc_func || !calloc_func || !realloc_func || !free_func) { // if not all are NULL, none of them can be NULL.
+ return false; // do _not_ set an error message in here, since it will allocate memory!
+ } else {
+ s_mem.malloc_func = malloc_func;
+ s_mem.calloc_func = calloc_func;
+ s_mem.realloc_func = realloc_func;
+ s_mem.free_func = free_func;
}
-
- s_mem.malloc_func = malloc_func;
- s_mem.calloc_func = calloc_func;
- s_mem.realloc_func = realloc_func;
- s_mem.free_func = free_func;
return true;
}