From b0e93e4e63e825329e6b10072d172f808d7fcd9b Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 3 Jun 2024 04:09:28 -0700
Subject: [PATCH] Prevent crashes if freed objects are passed to SDL API
functions
Instead of using the magic tag in the object, we'll actually keep track of valid objects
Fixes https://github.com/libsdl-org/SDL/issues/9869
Fixes https://github.com/libsdl-org/SDL/issues/9235
---
src/SDL.c | 15 +----
src/SDL_hashtable.c | 28 ++++++++-
src/SDL_internal.h | 3 +-
src/SDL_utils.c | 67 +++++++++++++++++++++-
src/SDL_utils_c.h | 20 +++++++
src/audio/SDL_audio.c | 1 -
src/audio/dsp/SDL_dspaudio.c | 1 -
src/events/SDL_keyboard.c | 2 +-
src/haptic/SDL_haptic.c | 7 +--
src/haptic/SDL_syshaptic.h | 2 -
src/hidapi/SDL_hidapi.c | 26 ++++-----
src/joystick/SDL_gamepad.c | 22 +++----
src/joystick/SDL_joystick.c | 18 +++---
src/joystick/SDL_joystick_c.h | 1 -
src/joystick/SDL_sysjoystick.h | 2 -
src/joystick/hidapi/SDL_hidapijoystick.c | 7 +--
src/joystick/hidapi/SDL_hidapijoystick_c.h | 1 -
src/joystick/linux/SDL_sysjoystick.c | 28 +++++----
src/render/SDL_render.c | 25 ++++----
src/render/SDL_sysrender.h | 5 --
src/render/opengl/SDL_render_gl.c | 1 -
src/sensor/SDL_sensor.c | 15 ++---
src/sensor/SDL_syssensor.h | 2 -
src/video/SDL_sysvideo.h | 2 -
src/video/SDL_video.c | 10 ++--
src/video/wayland/SDL_waylandwindow.c | 4 +-
src/video/x11/SDL_x11events.c | 1 -
src/video/x11/SDL_x11window.c | 1 -
28 files changed, 191 insertions(+), 126 deletions(-)
diff --git a/src/SDL.c b/src/SDL.c
index 2504d0338e3b2..86c75f05be378 100644
--- a/src/SDL.c
+++ b/src/SDL.c
@@ -543,6 +543,7 @@ void SDL_Quit(void)
SDL_DBus_Quit();
#endif
+ SDL_SetObjectsInvalid();
SDL_ClearHints();
SDL_AssertionsQuit();
@@ -563,20 +564,6 @@ void SDL_Quit(void)
SDL_bInMainQuit = SDL_FALSE;
}
-/* Assume we can wrap SDL_AtomicInt values and cast to Uint32 */
-SDL_COMPILE_TIME_ASSERT(sizeof_object_id, sizeof(int) == sizeof(Uint32));
-
-Uint32 SDL_GetNextObjectID(void)
-{
- static SDL_AtomicInt last_id;
-
- Uint32 id = (Uint32)SDL_AtomicIncRef(&last_id) + 1;
- if (id == 0) {
- id = (Uint32)SDL_AtomicIncRef(&last_id) + 1;
- }
- return id;
-}
-
/* Get the library version number */
int SDL_GetVersion(void)
{
diff --git a/src/SDL_hashtable.c b/src/SDL_hashtable.c
index 25b893b6a37d1..240dd9f55866f 100644
--- a/src/SDL_hashtable.c
+++ b/src/SDL_hashtable.c
@@ -83,6 +83,10 @@ SDL_bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const vo
SDL_HashItem *item;
const Uint32 hash = calc_hash(table, key);
+ if (!table) {
+ return SDL_FALSE;
+ }
+
if ( (!table->stackable) && (SDL_FindInHashTable(table, key, NULL)) ) {
return SDL_FALSE;
}
@@ -107,6 +111,10 @@ SDL_bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const
void *data = table->data;
SDL_HashItem *i;
+ if (!table) {
+ return SDL_FALSE;
+ }
+
for (i = table->table[hash]; i; i = i->next) {
if (table->keymatch(key, i->key, data)) {
if (_value) {
@@ -126,6 +134,10 @@ SDL_bool SDL_RemoveFromHashTable(SDL_HashTable *table, const void *key)
SDL_HashItem *prev = NULL;
void *data = table->data;
+ if (!table) {
+ return SDL_FALSE;
+ }
+
for (item = table->table[hash]; item; item = item->next) {
if (table->keymatch(key, item->key, data)) {
if (prev) {
@@ -134,7 +146,9 @@ SDL_bool SDL_RemoveFromHashTable(SDL_HashTable *table, const void *key)
table->table[hash] = item->next;
}
- table->nuke(item->key, item->value, data);
+ if (table->nuke) {
+ table->nuke(item->key, item->value, data);
+ }
SDL_free(item);
return SDL_TRUE;
}
@@ -149,6 +163,10 @@ SDL_bool SDL_IterateHashTableKey(const SDL_HashTable *table, const void *key, co
{
SDL_HashItem *item = *iter ? ((SDL_HashItem *) *iter)->next : table->table[calc_hash(table, key)];
+ if (!table) {
+ return SDL_FALSE;
+ }
+
while (item) {
if (table->keymatch(key, item->key, table->data)) {
*_value = item->value;
@@ -169,6 +187,10 @@ SDL_bool SDL_IterateHashTable(const SDL_HashTable *table, const void **_key, con
SDL_HashItem *item = (SDL_HashItem *) *iter;
Uint32 idx = 0;
+ if (!table) {
+ return SDL_FALSE;
+ }
+
if (item) {
const SDL_HashItem *orig = item;
item = item->next;
@@ -219,7 +241,9 @@ void SDL_DestroyHashTable(SDL_HashTable *table)
SDL_HashItem *item = table->table[i];
while (item) {
SDL_HashItem *next = item->next;
- table->nuke(item->key, item->value, data);
+ if (table->nuke) {
+ table->nuke(item->key, item->value, data);
+ }
SDL_free(item);
item = next;
}
diff --git a/src/SDL_internal.h b/src/SDL_internal.h
index e407cdaff1171..a1bdbdec2f886 100644
--- a/src/SDL_internal.h
+++ b/src/SDL_internal.h
@@ -279,6 +279,8 @@
#define SDL_MAIN_NOIMPL /* don't drag in header-only implementation of SDL_main */
#include <SDL3/SDL_main.h>
+#include "SDL_utils_c.h"
+
/* The internal implementations of these functions have up to nanosecond precision.
We can expose these functions as part of the API if we want to later.
*/
@@ -287,7 +289,6 @@
extern "C" {
#endif
-extern Uint32 SDLCALL SDL_GetNextObjectID(void);
extern int SDLCALL SDL_WaitSemaphoreTimeoutNS(SDL_Semaphore *sem, Sint64 timeoutNS);
extern int SDLCALL SDL_WaitConditionTimeoutNS(SDL_Condition *cond, SDL_Mutex *mutex, Sint64 timeoutNS);
extern SDL_bool SDLCALL SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS);
diff --git a/src/SDL_utils.c b/src/SDL_utils.c
index e2ce2939d7a19..7efbe4400596a 100644
--- a/src/SDL_utils.c
+++ b/src/SDL_utils.c
@@ -20,7 +20,7 @@
*/
#include "SDL_internal.h"
-#include "SDL_utils_c.h"
+#include "SDL_hashtable.h"
/* Common utility functions that aren't in the public API */
@@ -100,3 +100,68 @@ SDL_bool SDL_endswith(const char *string, const char *suffix)
}
return SDL_FALSE;
}
+
+/* Assume we can wrap SDL_AtomicInt values and cast to Uint32 */
+SDL_COMPILE_TIME_ASSERT(sizeof_object_id, sizeof(int) == sizeof(Uint32));
+
+Uint32 SDL_GetNextObjectID(void)
+{
+ static SDL_AtomicInt last_id;
+
+ Uint32 id = (Uint32)SDL_AtomicIncRef(&last_id) + 1;
+ if (id == 0) {
+ id = (Uint32)SDL_AtomicIncRef(&last_id) + 1;
+ }
+ return id;
+}
+
+static SDL_HashTable *SDL_objects;
+
+static Uint32 SDL_HashObject(const void *key, void *unused)
+{
+ return (Uint32)(uintptr_t)key;
+}
+
+static SDL_bool SDL_KeyMatchObject(const void *a, const void *b, void *unused)
+{
+ return (a == b);
+}
+
+void SDL_SetObjectValid(void *object, SDL_ObjectType type, SDL_bool valid)
+{
+ SDL_assert(object != NULL);
+
+ if (valid) {
+ if (!SDL_objects) {
+ SDL_objects = SDL_CreateHashTable(NULL, 32, SDL_HashObject, SDL_KeyMatchObject, NULL, SDL_FALSE);
+ }
+
+ SDL_InsertIntoHashTable(SDL_objects, object, (void *)(uintptr_t)type);
+ } else {
+ if (SDL_objects) {
+ SDL_RemoveFromHashTable(SDL_objects, object);
+ }
+ }
+}
+
+SDL_bool SDL_ObjectValid(void *object, SDL_ObjectType type)
+{
+ if (!object) {
+ return SDL_FALSE;
+ }
+
+ const void *object_type;
+ if (!SDL_FindInHashTable(SDL_objects, object, &object_type)) {
+ return SDL_FALSE;
+ }
+
+ return (((SDL_ObjectType)(uintptr_t)object_type) == type);
+}
+
+void SDL_SetObjectsInvalid(void)
+{
+ if (SDL_objects) {
+ SDL_DestroyHashTable(SDL_objects);
+ SDL_objects = NULL;
+ }
+}
diff --git a/src/SDL_utils_c.h b/src/SDL_utils_c.h
index bf0a4fc81ebe6..35d8543e8a04f 100644
--- a/src/SDL_utils_c.h
+++ b/src/SDL_utils_c.h
@@ -32,4 +32,24 @@ extern void SDL_CalculateFraction(float x, int *numerator, int *denominator);
extern SDL_bool SDL_endswith(const char *string, const char *suffix);
+typedef enum
+{
+ SDL_OBJECT_TYPE_UNKNOWN,
+ SDL_OBJECT_TYPE_WINDOW,
+ SDL_OBJECT_TYPE_RENDERER,
+ SDL_OBJECT_TYPE_TEXTURE,
+ SDL_OBJECT_TYPE_JOYSTICK,
+ SDL_OBJECT_TYPE_GAMEPAD,
+ SDL_OBJECT_TYPE_HAPTIC,
+ SDL_OBJECT_TYPE_SENSOR,
+ SDL_OBJECT_TYPE_HIDAPI_DEVICE,
+ SDL_OBJECT_TYPE_HIDAPI_JOYSTICK,
+
+} SDL_ObjectType;
+
+extern Uint32 SDL_GetNextObjectID(void);
+extern void SDL_SetObjectValid(void *object, SDL_ObjectType type, SDL_bool valid);
+extern SDL_bool SDL_ObjectValid(void *object, SDL_ObjectType type);
+extern void SDL_SetObjectsInvalid(void);
+
#endif /* SDL_utils_h_ */
diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index 98d6712c39d16..521333ec0ae9e 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -23,7 +23,6 @@
#include "SDL_audio_c.h"
#include "SDL_sysaudio.h"
#include "../thread/SDL_systhread.h"
-#include "../SDL_utils_c.h"
// Available audio drivers
static const AudioBootStrap *const bootstrap[] = {
diff --git a/src/audio/dsp/SDL_dspaudio.c b/src/audio/dsp/SDL_dspaudio.c
index e9412e083410f..053cc3d09030c 100644
--- a/src/audio/dsp/SDL_dspaudio.c
+++ b/src/audio/dsp/SDL_dspaudio.c
@@ -37,7 +37,6 @@
#include <sys/soundcard.h>
#include "../SDL_audiodev_c.h"
-#include "../../SDL_utils_c.h"
#include "SDL_dspaudio.h"
static void DSP_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c
index 7e5accde64eea..b6336582ae5ec 100644
--- a/src/events/SDL_keyboard.c
+++ b/src/events/SDL_keyboard.c
@@ -891,7 +891,7 @@ int SDL_SetKeyboardFocus(SDL_Window *window)
SDL_Keyboard *keyboard = &SDL_keyboard;
if (window) {
- if (!video || window->magic != &video->window_magic || window->is_destroying) {
+ if (!SDL_ObjectValid(window, SDL_OBJECT_TYPE_WINDOW) || window->is_destroying) {
return SDL_SetError("Invalid window");
}
}
diff --git a/src/haptic/SDL_haptic.c b/src/haptic/SDL_haptic.c
index d4502b11503f8..795cff1affb63 100644
--- a/src/haptic/SDL_haptic.c
+++ b/src/haptic/SDL_haptic.c
@@ -25,10 +25,9 @@
#include "../joystick/SDL_joystick_c.h" /* For SDL_IsJoystickValid */
static SDL_Haptic *SDL_haptics = NULL;
-static char SDL_haptic_magic;
#define CHECK_HAPTIC_MAGIC(haptic, retval) \
- if (!haptic || haptic->magic != &SDL_haptic_magic) { \
+ if (!SDL_ObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC)) { \
SDL_InvalidParamError("haptic"); \
return retval; \
}
@@ -135,7 +134,7 @@ SDL_Haptic *SDL_OpenHaptic(SDL_HapticID instance_id)
}
/* Initialize the haptic device */
- haptic->magic = &SDL_haptic_magic;
+ SDL_SetObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC, SDL_TRUE);
haptic->instance_id = instance_id;
haptic->rumble_id = -1;
if (SDL_SYS_HapticOpen(haptic) < 0) {
@@ -318,7 +317,7 @@ void SDL_CloseHaptic(SDL_Haptic *haptic)
}
}
SDL_SYS_HapticClose(haptic);
- haptic->magic = NULL;
+ SDL_SetObjectValid(haptic, SDL_OBJECT_TYPE_HAPTIC, SDL_FALSE);
/* Remove from the list */
hapticlist = SDL_haptics;
diff --git a/src/haptic/SDL_syshaptic.h b/src/haptic/SDL_syshaptic.h
index a0cba77cdbff4..83b8dd200c216 100644
--- a/src/haptic/SDL_syshaptic.h
+++ b/src/haptic/SDL_syshaptic.h
@@ -40,8 +40,6 @@ struct haptic_effect
*/
struct SDL_Haptic
{
- const void *magic;
-
SDL_HapticID instance_id; /* Device instance, monotonically increasing from 0 */
char *name; /* Device name - system dependent */
diff --git a/src/hidapi/SDL_hidapi.c b/src/hidapi/SDL_hidapi.c
index 3b5fbbf18b01d..930db26df2097 100644
--- a/src/hidapi/SDL_hidapi.c
+++ b/src/hidapi/SDL_hidapi.c
@@ -1000,19 +1000,17 @@ static const struct hidapi_backend LIBUSB_Backend = {
struct SDL_hid_device
{
- const void *magic;
void *device;
const struct hidapi_backend *backend;
SDL_hid_device_info info;
};
-static char device_magic;
#if defined(HAVE_PLATFORM_BACKEND) || defined(HAVE_DRIVER_BACKEND) || defined(HAVE_LIBUSB)
static SDL_hid_device *CreateHIDDeviceWrapper(void *device, const struct hidapi_backend *backend)
{
SDL_hid_device *wrapper = (SDL_hid_device *)SDL_malloc(sizeof(*wrapper));
- wrapper->magic = &device_magic;
+ SDL_SetObjectValid(wrapper, SDL_OBJECT_TYPE_HIDAPI_DEVICE, SDL_TRUE);
wrapper->device = device;
wrapper->backend = backend;
SDL_zero(wrapper->info);
@@ -1021,20 +1019,20 @@ static SDL_hid_device *CreateHIDDeviceWrapper(void *device, const struct hidapi_
#endif /* HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || HAVE_LIBUSB */
-static void DeleteHIDDeviceWrapper(SDL_hid_device *device)
+static void DeleteHIDDeviceWrapper(SDL_hid_device *wrapper)
{
- device->magic = NULL;
- SDL_free(device->info.path);
- SDL_free(device->info.serial_number);
- SDL_free(device->info.manufacturer_string);
- SDL_free(device->info.product_string);
- SDL_free(device);
+ SDL_SetObjectValid(wrapper, SDL_OBJECT_TYPE_HIDAPI_DEVICE, SDL_FALSE);
+ SDL_free(wrapper->info.path);
+ SDL_free(wrapper->info.serial_number);
+ SDL_free(wrapper->info.manufacturer_string);
+ SDL_free(wrapper->info.product_string);
+ SDL_free(wrapper);
}
-#define CHECK_DEVICE_MAGIC(device, retval) \
- if (!device || device->magic != &device_magic) { \
- SDL_SetError("Invalid device"); \
- return retval; \
+#define CHECK_DEVICE_MAGIC(device, retval) \
+ if (!SDL_ObjectValid(device, SDL_OBJECT_TYPE_HIDAPI_DEVICE)) { \
+ SDL_SetError("Invalid device"); \
+ return retval; \
}
#define COPY_IF_EXISTS(var) \
diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c
index d400b53ae3b34..50b122f752819 100644
--- a/src/joystick/SDL_gamepad.c
+++ b/src/joystick/SDL_gamepad.c
@@ -22,7 +22,6 @@
/* This is the gamepad API for Simple DirectMedia Layer */
-#include "../SDL_utils_c.h"
#include "SDL_sysjoystick.h"
#include "SDL_joystick_c.h"
#include "SDL_steam_virtual_gamepad.h"
@@ -104,15 +103,12 @@ static GamepadMapping_t *s_pSupportedGamepads SDL_GUARDED_BY(SDL_joystick_lock)
static GamepadMapping_t *s_pDefaultMapping SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
static GamepadMapping_t *s_pXInputMapping SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
static MappingChangeTracker *s_mappingChangeTracker SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
-static char gamepad_magic;
#define _guarded SDL_GUARDED_BY(SDL_joystick_lock)
/* The SDL gamepad structure */
struct SDL_Gamepad
{
- const void *magic _guarded;
-
SDL_Joystick *joystick _guarded; /* underlying joystick device */
int ref_count _guarded;
@@ -131,12 +127,12 @@ struct SDL_Gamepad
#undef _guarded
-#define CHECK_GAMEPAD_MAGIC(gamepad, retval) \
- if (!gamepad || gamepad->magic != &gamepad_magic || \
- !SDL_IsJoystickValid(gamepad->joystick)) { \
- SDL_InvalidParamError("gamepad"); \
- SDL_UnlockJoysticks(); \
- return retval; \
+#define CHECK_GAMEPAD_MAGIC(gamepad, retval) \
+ if (!SDL_ObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD) || \
+ !SDL_IsJoystickValid(gamepad->joystick)) { \
+ SDL_InvalidParamError("gamepad"); \
+ SDL_UnlockJoysticks(); \
+ return retval; \
}
static SDL_vidpid_list SDL_allowed_gamepads = {
@@ -2683,7 +2679,7 @@ SDL_Gamepad *SDL_OpenGamepad(SDL_JoystickID instance_id)
SDL_UnlockJoysticks();
return NULL;
}
- gamepad->magic = &gamepad_magic;
+ SDL_SetObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD, SDL_TRUE);
gamepad->joystick = SDL_OpenJoystick(instance_id);
if (!gamepad->joystick) {
@@ -3612,7 +3608,7 @@ void SDL_CloseGamepad(SDL_Gamepad *gamepad)
SDL_LockJoysticks();
- if (!gamepad || gamepad->magic != &gamepad_magic) {
+ if (!SDL_ObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD)) {
SDL_UnlockJoysticks();
return;
}
@@ -3641,7 +3637,7 @@ void SDL_CloseGamepad(SDL_Gamepad *gamepad)
gamepadlist = gamepadlist->next;
}
- gamepad->magic = NULL;
+ SDL_SetObjectValid(gamepad, SDL_OBJECT_TYPE_GAMEPAD, SDL_FALSE);
SDL_free(gamepad->bindings);
SDL_free(gamepad->last_match_axis);
SDL_free(gamepad->last_hat_mask);
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index b913c15bf10ef..001180453c751 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -121,7 +121,6 @@ static SDL_Joystick *SDL_joysticks SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
static int SDL_joystick_player_count SDL_GUARDED_BY(SDL_joystick_lock) = 0;
static SDL_JoystickID *SDL_joystick_players SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
static SDL_bool SDL_joystick_allows_background_events = SDL_FALSE;
-char SDL_joystick_magic;
static Uint32 initial_arcadestick_devices[] = {
MAKE_VIDPID(0x0079, 0x181a), /* Venom Arcade Stick */
@@ -415,11 +414,11 @@ static SDL_vidpid_list zero_centered_devices = {
SDL_FALSE
};
-#define CHECK_JOYSTICK_MAGIC(joystick, retval) \
- if (!joystick || joystick->magic != &SDL_joystick_magic) { \
- SDL_InvalidParamError("joystick"); \
- SDL_UnlockJoysticks(); \
- return retval; \
+#define CHECK_JOYSTICK_MAGIC(joystick, retval) \
+ if (!SDL_ObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK)) { \
+ SDL_InvalidParamError("joystick"); \
+ SDL_UnlockJoysticks(); \
+ return retval; \
}
SDL_bool SDL_JoysticksInitialized(void)
@@ -1096,7 +1095,7 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
SDL_UnlockJoysticks();
return NULL;
}
- joystick->magic = &SDL_joystick_magic;
+ SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, SDL_TRUE);
joystick->driver = driver;
joystick->instance_id = instance_id;
joystick->attached = SDL_TRUE;
@@ -1104,6 +1103,7 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
joystick->battery_percent = -1;
if (driver->Open(joystick, device_index) < 0) {
+ SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, SDL_FALSE);
SDL_free(joystick);
SDL_UnlockJoysticks();
return NULL;
@@ -1346,7 +1346,7 @@ int SDL_SendJoystickVirtualSensorData(SDL_Joystick *joystick, SDL_SensorType typ
SDL_bool SDL_IsJoystickValid(SDL_Joystick *joystick)
{
SDL_AssertJoysticksLocked();
- return (joystick && joystick->magic == &SDL_joystick_magic);
+ return SDL_ObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK);
}
SDL_bool SDL_PrivateJoystickGetAutoGamepadMapping(SDL_JoystickID instance_id, SDL_GamepadMapping *out)
@@ -1869,7 +1869,7 @@ void SDL_CloseJoystick(SDL_Joystick *joystick)
joystick->driver->Close(joystick);
joystick->hwdata = NULL;
- joystick->magic = NULL;
+ SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, SDL_FALSE);
joysticklist = SDL_joysticks;
joysticklistprev = NULL;
diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h
index b45c594d5c9f4..7fc6645192fd0 100644
--- a/src/joystick/SDL_joystick_c.h
+++ b/src/joystick/SDL_joystick_c.h
@@ -33,7 +33,6 @@ extern "C" {
struct SDL_JoystickDriver;
struct SDL_SteamVirtualGamepadInfo;
-extern char SDL_joystick_magic;
/* Initialization and shutdown functions */
extern int SDL_InitJoysticks(void);
diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h
index d6c50aff6371f..52bcd17d36598 100644
--- a/src/joystick/SDL_sysjoystick.h
+++ b/src/joystick/SDL_sysjoystick.h
@@ -76,8 +76,6 @@ typedef struct SDL_JoystickSensorInfo
struct SDL_Joystick
{
- const void *magic _guarded;
-
SDL_JoystickID instance_id _guarded; /* Device instance, monotonically increasing from 0 */
char *name _guarded; /* Joystick name - system dependent */
char *path _guarded; /* Joystick path - system dependent */
diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c
index 07d8934f4f785..cdd6de9883279 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick.c
+++ b/src/joystick/hidapi/SDL_hidapijoystick.c
@@ -91,7 +91,6 @@ static SDL_SpinLock SDL_HIDAPI_spinlock;
static SDL_bool SDL_HIDAPI_hints_changed = SDL_FALSE;
static Uint32 SDL_HIDAPI_change_count = 0;
static SDL_HIDAPI_Device *SDL_HIDAPI_devices SDL_GUARDED_BY(SDL_joystick_lock);
-static char SDL_HIDAPI_device_magic;
static int SDL_HIDAPI_numjoysticks = 0;
static SDL_bool SDL_HIDAPI_combine_joycons = SDL_TRUE;
static SDL_bool initialized = SDL_FALSE;
@@ -933,7 +932,7 @@ static SDL_HIDAPI_Device *HIDAPI_AddDevice(const struct SDL_hid_device_info *inf
if (!device) {
return NULL;
}
- device->magic = &SDL_HIDAPI_device_magic;
+ SDL_SetObjectValid(device, SDL_OBJECT_TYPE_HIDAPI_JOYSTICK, SDL_TRUE);
device->path = SDL_strdup(info->path);
if (!device->path) {
SDL_free(device);
@@ -1049,7 +1048,7 @@ static void HIDAPI_DelDevice(SDL_HIDAPI_Device *device)
device->children[i]->parent = NULL;
}
- device->magic = NULL;
+ SDL_SetObjectValid(device, SDL_OBJECT_TYPE_HIDAPI_JOYSTICK, SDL_FALSE);
SDL_DestroyMutex(device->dev_lock);
SDL_free(device->manufacturer_string);
SDL_free(device->product_string);
@@ -1547,7 +1546,7 @@ static SDL_bool HIDAPI_GetJoystickDevice(SDL_Joystick *joystick, SDL_HIDAPI_Devi
if (joystick && joystick->hwdata) {
*device = joystick->hwdata->device;
- if (*device && (*device)->magic == &SDL_HIDAPI_device_magic && (*device)->driver != NULL) {
+ if (SDL_ObjectValid(*device, SDL_OBJECT_TYPE_HIDAPI_JOYSTICK) && (*device)->driver != NULL) {
return SDL_TRUE;
}
}
diff --git a/src/joystick/hidapi/SDL_hidapijoystick_c.h b/src/joystick/hidapi/SDL_hidapijoystick_c.h
index 45fa9ec5b4465..c82421ef3d0b9 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick_c.h
+++ b/src/joystick/hidapi/SDL_hidapijoystick_c.h
@@ -66,7 +66,6 @@ struct SDL_HIDAPI_DeviceDriver;
typedef struct SDL_HIDAPI_Device
{
- const void *magic;
char *name;
char *manufacturer_string;
char *product_string;
diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c
index 345e4a9b11716..d6e5145fa7448 100644
--- a/src/joystick/linux/SDL_sysjoystick.c
+++ b/src/joystick/linux/SDL_sysjoystick.c
@@ -41,7 +41,6 @@
#include <dirent.h>
#include <linux/joystick.h>
-#include "../../SDL_utils_c.h"
#include "../../events/SDL_events_c.h"
#include "../../core/linux/SDL_evdev.h"
#include "../SDL_sysjoystick.h"
@@ -2330,6 +2329,7 @@ static SDL_bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap
MAPPED_DPAD_ALL = 0xF,
};
unsigned int mapped;
+ SDL_bool result = SDL_FALSE;
SDL_AssertJoysticksLocked();
@@ -2351,22 +2351,19 @@ static SDL_bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap
if (!joystick) {
return SDL_FALSE;
}
- joystick->magic = &SDL_joystick_magic;
SDL_memcpy(&joystick->guid, &item->guid, sizeof(item->guid));
- joystick->hwdata = (struct joystick_hwdata *)
- SDL_calloc(1, sizeof(*joystick->hwdata));
+ joystick->hwdata = (struct joystick_hwdata *)SDL_calloc(1, sizeof(*joystick->hwdata));
if (!joystick->hwdata) {
SDL_free(joystick);
return SDL_FALSE;
}
+ SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, SDL_TRUE);
item->checked_mapping = SDL_TRUE;
- if (PrepareJoystickHwdata(joystick, item, NULL) == -1) {
- SDL_free(joystick->hwdata);
- SDL_free(joystick);
- return SDL_FALSE; /* SDL_SetError will already have been called */
+ if (PrepareJoystickHwdata(joystick, item, NULL) < 0) {
+ goto done; /* SDL_SetError will already have been called */
}
/* don't assign `item->hwdata` so it's not in any global state. */
@@ -2375,9 +2372,7 @@ static SDL_bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap
if (!joystick->hwdata->has_key[BTN_GAMEPAD]) {
/* Not a gamepad according to the specs. */
- LINUX_JoystickClose(joystick);
- SDL_free(joystick);
- return SDL_FALSE;
+ goto done;
}
/* We have a gamepad, start filling out the mappings */
@@ -2773,9 +2768,6 @@ static SDL_bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap
}
}
- LINUX_JoystickClose(joystick);
- SDL_free(joystick);
-
/* Cache the mapping for later */
item->mapping = (SDL_GamepadMapping *)SDL_malloc(sizeof(*item->mapping));
if (item->mapping) {
@@ -2784,8 +2776,14 @@ static SDL_bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap
#ifdef DEBUG_GAMEPAD_MAPPING
SDL_Log("Generated mapping for device %d", device_index);
#endif
+ result = SDL_TRUE;
- return SDL_TRUE;
+done:
+ LINUX_JoystickClose(joystick);
+ SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, SDL_FALSE);
+ SDL_free(joystick);
+
+ return result;
}
SDL_JoystickDriver SDL_LINUX_JoystickDriver = {
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index 24daf9a0b1b2c..a32bcf3667e4f 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -46,10 +46,10 @@ this should probably be removed at some point in the future. --ryan. */
#define SDL_PROP_WINDOW_RENDERER_POINTER "SDL.internal.window.renderer"
#define SDL_PROP_TEXTURE_PARENT_POINTER "SDL.internal.texture.parent"
-#define CHECK_RENDERER_MAGIC_BUT_NOT_DESTROYED_FLAG(renderer, retval) \
- if (!(renderer) || (renderer)->magic != &SDL_renderer_magic) { \
- SDL_InvalidParamError("renderer"); \
- return retval; \
+#define CHECK_RENDERER_MAGIC_BUT_NOT_DESTROYED_FLAG(renderer, retval) \
+ if (!SDL_ObjectValid(renderer, SDL_OBJECT_TYPE_RENDERER)) { \
+ SDL_InvalidParamError("renderer"); \
+ return retval; \
}
#define CHECK_RENDERER_MAGIC(renderer, retval) \
@@ -60,7 +60,7 @@ this should probably be removed at some point in the future. --ryan. */
}
#define CHECK_TEXTURE_MAGIC(texture, retval) \
- if (!(texture) || (texture)->magic != &SDL_texture_magic) { \
+ if (!SDL_ObjectValid(texture, SDL_OBJECT_TYPE_TEXTURE)) { \
SDL_InvalidParamError("texture"); \
return retval; \
}
@@ -133,9 +133,6 @@ static const SDL_RenderDriver *render_drivers[] = {
};
#endif /* !SDL_RENDER_DISABLED */
-char SDL_renderer_magic;
-char SDL_texture_magic;
-
int SDL_AddSupportedTextureFormat(SDL_Renderer *renderer, SDL_PixelFormatEnum format)
{
@@ -946,7 +943,7 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
return NULL;
}
- renderer->magic = &SDL_renderer_magic;
+ SDL_SetObjectValid(renderer, SDL_OBJECT_TYPE_RENDERER, SDL_TRUE);
#ifdef SDL_PLATFORM_ANDROID
Android_ActivityMutex_Lock_Running();
@@ -1007,7 +1004,6 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
break; // Yay, we got one!
}
SDL_zerop(renderer); // make sure we don't leave function pointers from a previous CreateRenderer() in this struct.
- renderer->magic = &SDL_renderer_magic;
}
}
@@ -1021,7 +1017,6 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
VerifyDrawQueueFunctions(renderer);
- renderer->magic = &SDL_renderer_magic;
renderer->window = window;
renderer->target_mutex = SDL_CreateMutex();
if (surface) {
@@ -1114,6 +1109,8 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
error:
+ SDL_SetObjectValid(renderer, SDL_OBJECT_TYPE_RENDERER, SDL_FALSE);
+
#ifdef SDL_PLATFORM_ANDROID
Android_ActivityMutex_Unlock();
#endif
@@ -1316,7 +1313,7 @@ SDL_Texture *SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_Propert
if (!texture) {
return NULL;
}
- texture->magic = &SDL_texture_magic;
+ SDL_SetObjectValid(texture, SDL_OBJECT_TYPE_TEXTURE, SDL_TRUE);
texture->colorspace = (SDL_Colorspace)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, default_colorspace);
texture->format = format;
texture->access = access;
@@ -4496,7 +4493,7 @@ static int SDL_DestroyTextureInternal(SDL_Texture *texture, SDL_bool is_destroyi
renderer->logical_target = NULL;
}
- texture->magic = NULL;
+ SDL_SetObjectValid(texture, SDL_OBJECT_TYPE_TEXTURE, SDL_FALSE);
if (texture->next) {
texture->next->prev = texture->prev;
@@ -4596,7 +4593,7 @@ void SDL_DestroyRenderer(SDL_Renderer *renderer)
// in either order.
if (!renderer->destroyed) {
SDL_DestroyRendererWithoutFreeing(renderer);
- renderer->magic = NULL; // It's no longer magical...
+ SDL_SetObjectValid(renderer, SDL_OBJECT_TYPE_RENDERER, SDL_FALSE); // It's no longer magical...
}
SDL_free((void *)renderer->info.texture_formats);
diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h
index d3556b7cc254d..63a4687125a0b 100644
--- a/src/render/SDL_sysrender.h
+++ b/src/render/SDL_sysrender.h
@@ -44,8 +44,6 @@ typedef struct SDL_DRect
/* The SDL 2D rendering system */
typedef struct SDL_RenderDriver SDL_RenderDriver;
-extern char SDL_renderer_magic;
-extern char SDL_texture_magic;
/* Rendering view state */
typedef struct SDL_RenderViewState
@@ -62,7 +60,6 @@ typedef struct SDL_RenderViewState
/* Define the SDL texture structure */
struct SDL_Texture
{
- const void *magic;
SDL_Colorspace colorspace; /**< The colorspace of the texture */
float SDR_white_point; /**< The SDR white point for this content */
float HDR_headroom; /**< The HDR headroom needed by this content */
@@ -160,8 +157,6 @@ typedef enum
/* De
(Patch may be truncated, please check the link at the top of this post.)