diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h index 7961157ccf3dd..352006bf2a7b7 100644 --- a/include/SDL3/SDL_hints.h +++ b/include/SDL3/SDL_hints.h @@ -591,6 +591,25 @@ extern "C" { */ #define SDL_HINT_CAMERA_DRIVER "SDL_CAMERA_DRIVER" +/** + * A variable that controls whether object validity checks are enabled. + * + * Object validity checks prevent undefined behaviour when passing invalid + * pointers to SDL functions. A function will return invalid argument error + * if you pass pointer to unitialized/freed SDL object. You may want to + * disable these checks to improve performance. + * + * The variable can be set to the following values: + * + * - "0": Disable object validity checks + * - "1": Enable object validity checks + * + * This hint should be set before SDL is initialized. + * + * \since This hint is avaliable since ??? + */ +#define SDL_HINT_CHECK_OBJECT_VALIDITY "SDL_CHECK_OBJECT_VALIDITY" + /** * A variable that limits what CPU features are available. * diff --git a/src/SDL_utils.c b/src/SDL_utils.c index f2090747a8d35..1e957ab383f86 100644 --- a/src/SDL_utils.c +++ b/src/SDL_utils.c @@ -137,6 +137,7 @@ Uint32 SDL_GetNextObjectID(void) static SDL_InitState SDL_objects_init; static SDL_HashTable *SDL_objects; +static bool check_validity = true; static Uint32 SDLCALL SDL_HashObject(void *unused, const void *key) { @@ -153,6 +154,11 @@ void SDL_SetObjectValid(void *object, SDL_ObjectType type, bool valid) SDL_assert(object != NULL); if (SDL_ShouldInit(&SDL_objects_init)) { + check_validity = SDL_GetHintBoolean(SDL_HINT_CHECK_OBJECT_VALIDITY, true); + if(!check_validity) { + SDL_SetInitialized(&SDL_objects_init, true); + return; + } SDL_objects = SDL_CreateHashTable(0, true, SDL_HashObject, SDL_KeyMatchObject, NULL, NULL); const bool initialized = (SDL_objects != NULL); SDL_SetInitialized(&SDL_objects_init, initialized); @@ -161,10 +167,12 @@ void SDL_SetObjectValid(void *object, SDL_ObjectType type, bool valid) } } - if (valid) { - SDL_InsertIntoHashTable(SDL_objects, object, (void *)(uintptr_t)type, true); - } else { - SDL_RemoveFromHashTable(SDL_objects, object); + if (check_validity) { + if (valid) { + SDL_InsertIntoHashTable(SDL_objects, object, (void *)(uintptr_t)type, true); + } else { + SDL_RemoveFromHashTable(SDL_objects, object); + } } } @@ -174,6 +182,10 @@ bool SDL_ObjectValid(void *object, SDL_ObjectType type) return false; } + if (!check_validity) { + return true; + } + const void *object_type; if (!SDL_FindInHashTable(SDL_objects, object, &object_type)) { return false; @@ -205,6 +217,9 @@ static bool SDLCALL GetOneObject(void *userdata, const SDL_HashTable *table, con int SDL_GetObjects(SDL_ObjectType type, void **objects, int count) { + if (!check_validity) { + return 0; + } GetOneObjectData data = { type, objects, count, 0 }; SDL_IterateHashTable(SDL_objects, GetOneObject, &data); return data.num_objects; @@ -236,11 +251,13 @@ static bool SDLCALL LogOneLeakedObject(void *userdata, const SDL_HashTable *tabl void SDL_SetObjectsInvalid(void) { if (SDL_ShouldQuit(&SDL_objects_init)) { - // Log any leaked objects - SDL_IterateHashTable(SDL_objects, LogOneLeakedObject, NULL); - SDL_assert(SDL_HashTableEmpty(SDL_objects)); - SDL_DestroyHashTable(SDL_objects); - SDL_objects = NULL; + if (check_validity) { + // Log any leaked objects + SDL_IterateHashTable(SDL_objects, LogOneLeakedObject, NULL); + SDL_assert(SDL_HashTableEmpty(SDL_objects)); + SDL_DestroyHashTable(SDL_objects); + SDL_objects = NULL; + } SDL_SetInitialized(&SDL_objects_init, false); } }