浏览代码

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 1 年之前
父节点
当前提交
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"