From 55908f14f8d1a154b7c91ba42b8f764776bc688a Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 5 Jun 2026 09:27:22 -0700
Subject: [PATCH] Added SDL_aligned_alloc_zero()
---
include/SDL3/SDL_stdinc.h | 28 +++++++++++++++++++++++++++-
src/dynapi/SDL_dynapi.exports | 1 +
src/dynapi/SDL_dynapi.sym | 1 +
src/dynapi/SDL_dynapi_overrides.h | 1 +
src/dynapi/SDL_dynapi_procs.h | 1 +
src/stdlib/SDL_stdlib.c | 14 ++++++++++++--
src/video/SDL_surface.c | 16 ++++++++++------
7 files changed, 53 insertions(+), 9 deletions(-)
diff --git a/include/SDL3/SDL_stdinc.h b/include/SDL3/SDL_stdinc.h
index e8f41543a0c84..49d424c0c15ec 100644
--- a/include/SDL3/SDL_stdinc.h
+++ b/include/SDL3/SDL_stdinc.h
@@ -1362,7 +1362,9 @@ extern SDL_DECLSPEC SDL_MALLOC void * SDLCALL SDL_malloc(size_t size);
*
* If the allocation is successful, the returned pointer is guaranteed to be
* aligned to either the *fundamental alignment* (`alignof(max_align_t)` in
- * C11 and later) or `2 * sizeof(void *)`, whichever is smaller.
+ * C11 and later) or `2 * sizeof(void *)`, whichever is smaller. Use
+ * SDL_aligned_alloc_zero() if you need to allocate memory aligned to an
+ * alignment greater than this guarantee.
*
* \param nmemb the number of elements in the array.
* \param size the size of each element of the array.
@@ -1616,6 +1618,30 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetMemoryFunctions(SDL_malloc_func malloc_f
*/
extern SDL_DECLSPEC SDL_MALLOC void * SDLCALL SDL_aligned_alloc(size_t alignment, size_t size);
+/**
+ * Allocate zero-initialized memory aligned to a specific alignment.
+ *
+ * The memory returned by this function must be freed with SDL_aligned_free(),
+ * _not_ SDL_free().
+ *
+ * If `alignment` is less than the size of `void *`, it will be increased to
+ * match that.
+ *
+ * The returned memory address will be a multiple of the alignment value, and
+ * the size of the memory allocated will be a multiple of the alignment value.
+ *
+ * \param alignment the alignment of the memory.
+ * \param size the size to allocate.
+ * \returns a pointer to the aligned memory, or NULL if allocation failed.
+ *
+ * \threadsafety It is safe to call this function from any thread.
+ *
+ * \since This function is available since SDL 3.6.0.
+ *
+ * \sa SDL_aligned_free
+ */
+extern SDL_DECLSPEC SDL_MALLOC void * SDLCALL SDL_aligned_alloc_zero(size_t alignment, size_t size);
+
/**
* Free memory allocated by SDL_aligned_alloc().
*
diff --git a/src/dynapi/SDL_dynapi.exports b/src/dynapi/SDL_dynapi.exports
index 9864557071c3e..4eb5b02e62f6b 100644
--- a/src/dynapi/SDL_dynapi.exports
+++ b/src/dynapi/SDL_dynapi.exports
@@ -1290,3 +1290,4 @@ _SDL_LoadJPG
_SDL_HasSVE2
_SDL_GamepadHasCapSense
_SDL_GetGamepadCapSense
+_SDL_aligned_alloc_zero
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index 3958a52aa60af..de5e49896f12e 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -1291,6 +1291,7 @@ SDL3_0.0.0 {
SDL_HasSVE2;
SDL_GamepadHasCapSense;
SDL_GetGamepadCapSense;
+ SDL_aligned_alloc_zero;
# extra symbols go here (don't modify this line)
local: *;
};
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index b54d32ae6dcf5..e471dac703108 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -1317,3 +1317,4 @@
#define SDL_HasSVE2 SDL_HasSVE2_REAL
#define SDL_GamepadHasCapSense SDL_GamepadHasCapSense_REAL
#define SDL_GetGamepadCapSense SDL_GetGamepadCapSense_REAL
+#define SDL_aligned_alloc_zero SDL_aligned_alloc_zero_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 4f8ac0ba0cbb4..d2a28315ca2bf 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -1325,3 +1325,4 @@ SDL_DYNAPI_PROC(SDL_Surface*,SDL_LoadJPG,(const char *a),(a),return)
SDL_DYNAPI_PROC(bool,SDL_HasSVE2,(void),(),return)
SDL_DYNAPI_PROC(bool,SDL_GamepadHasCapSense,(SDL_Gamepad *a,SDL_GamepadCapSenseType b),(a,b),return)
SDL_DYNAPI_PROC(bool,SDL_GetGamepadCapSense,(SDL_Gamepad *a,SDL_GamepadCapSenseType b),(a,b),return)
+SDL_DYNAPI_PROC(void*,SDL_aligned_alloc_zero,(size_t a,size_t b),(a,b),return)
diff --git a/src/stdlib/SDL_stdlib.c b/src/stdlib/SDL_stdlib.c
index 1c55dc984e7a4..8c33006308f69 100644
--- a/src/stdlib/SDL_stdlib.c
+++ b/src/stdlib/SDL_stdlib.c
@@ -523,7 +523,7 @@ int SDL_toupper(int x) { return ((x) >= 'a') && ((x) <= 'z') ? ('A' + ((x) - 'a'
int SDL_tolower(int x) { return ((x) >= 'A') && ((x) <= 'Z') ? ('a' + ((x) - 'A')) : (x); }
int SDL_isblank(int x) { return ((x) == ' ') || ((x) == '\t'); }
-void *SDL_aligned_alloc(size_t alignment, size_t size)
+static void *SDL_aligned_alloc_internal(size_t alignment, size_t size, bool clear_memory)
{
size_t padding;
Uint8 *result = NULL;
@@ -537,7 +537,7 @@ void *SDL_aligned_alloc(size_t alignment, size_t size)
if (SDL_size_add_check_overflow(size, alignment, &size) &&
SDL_size_add_check_overflow(size, sizeof(void *), &size) &&
SDL_size_add_check_overflow(size, padding, &size)) {
- void *original = SDL_malloc(size);
+ void *original = clear_memory ? SDL_calloc(1, size) : SDL_malloc(size);
if (original) {
// Make sure we have enough space to store the original pointer
result = (Uint8 *)original + sizeof(original);
@@ -557,6 +557,16 @@ void *SDL_aligned_alloc(size_t alignment, size_t size)
return result;
}
+void *SDL_aligned_alloc(size_t alignment, size_t size)
+{
+ return SDL_aligned_alloc_internal(alignment, size, false);
+}
+
+void *SDL_aligned_alloc_zero(size_t alignment, size_t size)
+{
+ return SDL_aligned_alloc_internal(alignment, size, true);
+}
+
void SDL_aligned_free(void *mem)
{
if (mem) {
diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c
index 03e435c191860..20bedee14e7be 100644
--- a/src/video/SDL_surface.c
+++ b/src/video/SDL_surface.c
@@ -230,19 +230,23 @@ static SDL_Surface *SDL_CreateSurfaceInternal(int width, int height, SDL_PixelFo
if (surface->w && surface->h && format != SDL_PIXELFORMAT_MJPG) {
surface->flags &= ~SDL_SURFACE_PREALLOCATED;
if (SDL_GetHintBoolean("SDL_SURFACE_MALLOC", false)) {
- surface->pixels = SDL_malloc(size);
+ if (clear_surface) {
+ surface->pixels = SDL_calloc(1, size);
+ } else {
+ surface->pixels = SDL_malloc(size);
+ }
} else {
surface->flags |= SDL_SURFACE_SIMD_ALIGNED;
- surface->pixels = SDL_aligned_alloc(SDL_GetSIMDAlignment(), size);
+ if (clear_surface) {
+ surface->pixels = SDL_aligned_alloc_zero(SDL_GetSIMDAlignment(), size);
+ } else {
+ surface->pixels = SDL_aligned_alloc(SDL_GetSIMDAlignment(), size);
+ }
}
if (!surface->pixels) {
SDL_DestroySurface(surface);
return NULL;
}
-
- if (clear_surface) {
- SDL_memset(surface->pixels, 0, size);
- }
}
return surface;
}