Browse Source

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
Sam Lantinga 10 months ago
parent
commit
b0e93e4e63

+ 1 - 14
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)
 {

+ 26 - 2
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;
             }

+ 2 - 1
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);

+ 66 - 1
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;
+    }
+}

+ 20 - 0
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_ */

+ 0 - 1
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[] = {

+ 0 - 1
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)

+ 1 - 1
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");
         }
     }

+ 3 - 4
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;

+ 0 - 2
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 */
 

+ 12 - 14
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)                \

+ 9 - 13
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);

+ 9 - 9
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;

+ 0 - 1
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);

+ 0 - 2
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 */

+ 3 - 4
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;
         }
     }

+ 0 - 1
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;

+ 13 - 15
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 = {

+ 11 - 14
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);

+ 0 - 5
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
 /* Define the SDL renderer structure */
 struct SDL_Renderer
 {
-    const void *magic;
-
     void (*WindowEvent)(SDL_Renderer *renderer, const SDL_WindowEvent *event);
     int (*GetOutputSize)(SDL_Renderer *renderer, int *w, int *h);
     SDL_bool (*SupportsBlendMode)(SDL_Renderer *renderer, SDL_BlendMode blendMode);

+ 0 - 1
src/render/opengl/SDL_render_gl.c

@@ -26,7 +26,6 @@
 #include "../SDL_sysrender.h"
 #include "SDL_shaders_gl.h"
 #include "../../video/SDL_pixels_c.h"
-#include "../../SDL_utils_c.h"
 
 #ifdef SDL_PLATFORM_MACOS
 #include <OpenGL/OpenGL.h>

+ 8 - 7
src/sensor/SDL_sensor.c

@@ -56,13 +56,12 @@ static SDL_AtomicInt SDL_sensor_lock_pending;
 static int SDL_sensors_locked;
 static SDL_bool SDL_sensors_initialized;
 static SDL_Sensor *SDL_sensors SDL_GUARDED_BY(SDL_sensor_lock) = NULL;
-static char SDL_sensor_magic;
 
-#define CHECK_SENSOR_MAGIC(sensor, retval)              \
-    if (!sensor || sensor->magic != &SDL_sensor_magic) { \
-        SDL_InvalidParamError("sensor");                \
-        SDL_UnlockSensors();                            \
-        return retval;                                  \
+#define CHECK_SENSOR_MAGIC(sensor, retval)                  \
+    if (!SDL_ObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR)) { \
+        SDL_InvalidParamError("sensor");                    \
+        SDL_UnlockSensors();                                \
+        return retval;                                      \
     }
 
 SDL_bool SDL_SensorsInitialized(void)
@@ -327,13 +326,14 @@ SDL_Sensor *SDL_OpenSensor(SDL_SensorID instance_id)
         SDL_UnlockSensors();
         return NULL;
     }
-    sensor->magic = &SDL_sensor_magic;
+    SDL_SetObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR, SDL_TRUE);
     sensor->driver = driver;
     sensor->instance_id = instance_id;
     sensor->type = driver->GetDeviceType(device_index);
     sensor->non_portable_type = driver->GetDeviceNonPortableType(device_index);
 
     if (driver->Open(sensor, device_index) < 0) {
+        SDL_SetObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR, SDL_FALSE);
         SDL_free(sensor);
         SDL_UnlockSensors();
         return NULL;
@@ -508,6 +508,7 @@ void SDL_CloseSensor(SDL_Sensor *sensor)
 
         sensor->driver->Close(sensor);
         sensor->hwdata = NULL;
+        SDL_SetObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR, SDL_FALSE);
 
         sensorlist = SDL_sensors;
         sensorlistprev = NULL;

+ 0 - 2
src/sensor/SDL_syssensor.h

@@ -32,8 +32,6 @@
 /* The SDL sensor structure */
 struct SDL_Sensor
 {
-    const void *magic _guarded;
-
     SDL_SensorID instance_id _guarded;   /* Device instance, monotonically increasing from 0 */
     char *name _guarded;                 /* Sensor name - system dependent */
     SDL_SensorType type _guarded;        /* Type of the sensor */

+ 0 - 2
src/video/SDL_sysvideo.h

@@ -37,7 +37,6 @@ typedef struct SDL_WindowData SDL_WindowData;
 /* Define the SDL window structure, corresponding to toplevel windows */
 struct SDL_Window
 {
-    const void *magic;
     SDL_WindowID id;
     char *title;
     SDL_Surface *icon;
@@ -371,7 +370,6 @@ struct SDL_VideoDevice
     SDL_Rect desktop_bounds;
     SDL_Window *windows;
     SDL_Window *grabbed_window;
-    Uint8 window_magic;
     Uint32 clipboard_sequence;
     SDL_ClipboardDataCallback clipboard_callback;
     SDL_ClipboardCleanupCallback clipboard_cleanup;

+ 5 - 5
src/video/SDL_video.c

@@ -141,7 +141,7 @@ static VideoBootStrap *bootstrap[] = {
         SDL_UninitializedVideo();                                       \
         return retval;                                                  \
     }                                                                   \
-    if (!(window) || (window)->magic != &_this->window_magic) {         \
+    if (!SDL_ObjectValid(window, SDL_OBJECT_TYPE_WINDOW)) {             \
         SDL_SetError("Invalid window");                                 \
         return retval;                                                  \
     }
@@ -2118,7 +2118,7 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props)
         }
     }
 
-    if ((flags & SDL_WINDOW_MODAL) && (!parent || parent->magic != &_this->window_magic)) {
+    if ((flags & SDL_WINDOW_MODAL) && !SDL_ObjectValid(parent, SDL_OBJECT_TYPE_WINDOW)) {
         SDL_SetError("Modal windows must specify a parent window");
         return NULL;
     }
@@ -2130,7 +2130,7 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props)
         }
 
         /* Tooltip and popup menu window must specify a parent window */
-        if (!parent || parent->magic != &_this->window_magic) {
+        if (!SDL_ObjectValid(parent, SDL_OBJECT_TYPE_WINDOW)) {
             SDL_SetError("Tooltip and popup menu windows must specify a parent window");
             return NULL;
         }
@@ -2236,7 +2236,7 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props)
     if (!window) {
         return NULL;
     }
-    window->magic = &_this->window_magic;
+    SDL_SetObjectValid(window, SDL_OBJECT_TYPE_WINDOW, SDL_TRUE);
     window->id = SDL_GetNextObjectID();
     window->floating.x = window->windowed.x = window->x = x;
     window->floating.y = window->windowed.y = window->y = y;
@@ -3920,7 +3920,7 @@ void SDL_DestroyWindow(SDL_Window *window)
     }
 
     /* Now invalidate magic */
-    window->magic = NULL;
+    SDL_SetObjectValid(window, SDL_OBJECT_TYPE_WINDOW, SDL_FALSE);
 
     /* Free memory associated with the window */
     SDL_free(window->title);

+ 2 - 2
src/video/wayland/SDL_waylandwindow.c

@@ -1252,7 +1252,7 @@ static void decoration_frame_configure(struct libdecor_frame *frame,
                 } else if (window->max_aspect && aspect > window->max_aspect) {
                     wind->requested.pixel_width = SDL_roundf((float)wind->requested.pixel_height * window->max_aspect);
                 }
-                
+
                 wind->requested.logical_width = PixelToPoint(window, wind->requested.pixel_width);
                 wind->requested.logical_height = PixelToPoint(window, wind->requested.pixel_height);
             }
@@ -1854,7 +1854,7 @@ static void Wayland_ReleasePopup(SDL_VideoDevice *_this, SDL_Window *popup)
     SDL_WindowData *popupdata;
 
     /* Basic sanity checks to weed out the weird popup closures */
-    if (!popup || popup->magic != &_this->window_magic) {
+    if (!SDL_ObjectValid(popup, SDL_OBJECT_TYPE_WINDOW)) {
         return;
     }
     popupdata = popup->driverdata;

+ 0 - 1
src/video/x11/SDL_x11events.c

@@ -39,7 +39,6 @@
 #include "../../events/SDL_mouse_c.h"
 #include "../../events/SDL_touch_c.h"
 #include "../../core/linux/SDL_system_theme.h"
-#include "../../SDL_utils_c.h"
 #include "../SDL_sysvideo.h"
 
 #include <stdio.h>

+ 0 - 1
src/video/x11/SDL_x11window.c

@@ -28,7 +28,6 @@
 #include "../../events/SDL_mouse_c.h"
 #include "../../events/SDL_events_c.h"
 #include "../../core/unix/SDL_appid.h"
-#include "../../SDL_utils_c.h"
 
 #include "SDL_x11video.h"
 #include "SDL_x11mouse.h"