From b04d026458cd762db3499bec54348e51acd76508 Mon Sep 17 00:00:00 2001
From: Daniel Gibson <[EMAIL REDACTED]>
Date: Fri, 12 Jun 2026 19:24:56 +0200
Subject: [PATCH] Add an invalid #define for SDL_ThreadID() to SDL_oldnames.h
(#15801)
in SDL2 SDL_ThreadID() was a function that's now
SDL_GetCurrentThreadID(), but in SDL3 SDL_ThreadID is a type, so
in C++ `x = SDL_ThreadID()` is valid code (default constructor which
in case of integers means 0), so that's a massive footgun.
See the big comment in SDL_oldnames.h for more details.
Added `#undef SDL_ThreadID` in SDL_dynapi.c because it has one of the
(quite rare) cases where "SDL_ThreadID" followed by a "(" is actually
correct and necessary (function pointer returning SDL_ThreadID).
---
docs/README-migration.md | 11 ++++++++
include/SDL3/SDL_oldnames.h | 54 +++++++++++++++++++++++++++++++++++++
src/dynapi/SDL_dynapi.c | 6 +++++
3 files changed, 71 insertions(+)
diff --git a/docs/README-migration.md b/docs/README-migration.md
index 3fd243c8f2a99..b77a9a28d164f 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -41,6 +41,8 @@ Many functions and symbols have been renamed. We have provided a handy Python sc
rename_symbols.py --all-symbols source_code_path
+Note that rename_symbols.py can’t completely handle SDL_ThreadID, see the SDL_Thread.h section below.
+
It’s also possible to apply a semantic patch to migrate more easily to SDL3: SDL_migration.cocci
SDL headers should now be included as #include <SDL3/SDL.h>. Typically that’s the only SDL header you’ll need in your application unless you are using OpenGL or Vulkan functionality. SDL_image, SDL_mixer, SDL_net, SDL_ttf and SDL_rtf have also their preferred include path changed: for SDL_image, it becomes #include <SDL3_image/SDL_image.h>. We have provided a handy Python script rename_headers.py to rename SDL2 headers to their SDL3 counterparts:
@@ -2046,6 +2048,15 @@ The following functions have been removed:
The following symbols have been renamed:
- SDL_threadID => SDL_ThreadID
+### Attention: Potential problems with SDL_ThreadID
+
+SDL_ThreadID is a case that needs special attention, because if you forget to rename a call to SDL_ThreadID() to SDL_GetCurrentThreadID() in C++ code, it will still compile fine, calling the default constructor of the SDL_ThreadID type, initializing it to 0 - but if SDL_GetCurrentThreadID() was intended, that of course leads to wrong behavior that can be hard to catch.
+
+Furthermore rename_symbols.py does not handle it (because it would be hard to do in a way that doesn’t break anything when running that script twice), which makes it even more error-prone.
+
+SDL_oldnames.h now has a #define that should catch these cases, but it’s not available in SDL 3.4.10 and older. So if you’re using 3.4.10 or older, check your code carefully for occurences of SDL_ThreadID() and make sure it wasn’t supposed to be SDL_GetCurrentThreadID().
+In some edge cases this #define can cause false positives (compile errors even though SDL_ThreadID was used correctly); right above that definition in the header is a long comment explaining possible problems and solutions.
+
SDL_timer.h
SDL_GetTicks() now returns a 64-bit value. Instead of using the SDL_TICKS_PASSED macro, you can directly compare tick values, e.g.
diff --git a/include/SDL3/SDL_oldnames.h b/include/SDL3/SDL_oldnames.h
index cbf045330769b..6fd95216f7d84 100644
— a/include/SDL3/SDL_oldnames.h
+++ b/include/SDL3/SDL_oldnames.h
@@ -1336,4 +1336,58 @@
#endif /* SDL_ENABLE_OLD_NAMES */
+/* In SDL2, SDL_ThreadID() was a function that is now called SDL_GetCurrentThreadID().
-
- In SDL3, the thread ID type is called
SDL_ThreadID(in SDL2 it was
- In SDL3, the thread ID type is called
-
SDL_threadIDwith lower ‘t’).
-
-
- Unfortunately, at least in C++ writing SDL_ThreadID() compiles fine even for
-
- the type, it’s the default constructor of the type, so e.g.
-
myID = SDL_ThreadID();is equivalent tomyID = 0;
-
-
- Of course if you’ve been porting SDL2 code and have missed renaming this case
-
- of
SDL_ThreadID()toSDL_GetCurrentThreadID()this is quite a pitfall:
- of
-
- The code compiles fine, but behaves wrong: it will set
myIDto0instead
- The code compiles fine, but behaves wrong: it will set
-
- of the current thread’s ID.
-
-
- This makes it impossible to provide a “proper”
SDL_ENABLE_OLD_NAMEStreatment
- This makes it impossible to provide a “proper”
-
- of SDL_ThreadID() in this header, so the following
#definesetsSDL_ThreadID()
- of SDL_ThreadID() in this header, so the following
-
- to an invalid value, forcing you to consciously adjust it to your needs, i.e.
-
- replacing it with
SDL_GetCurrentThreadID()or0depending on your intentions.
- replacing it with
-
-
- Note that using
SDL_ThreadID x = ...;is unaffected, only “SDL_ThreadID” followed
- Note that using
-
- by “(” will lead to a compile error.
-
-
- Unfortunately, there are some cases where this breaks legit SDL3 code that
-
- actually means to use
SDL_ThreadID(..., like:
- actually means to use
-
-
- Definitions of function pointers with SDL_ThreadID as return type, like
-
-
typedef SDL_ThreadID (SDLCALL *SDL_DYNAPIFN_SDL_GetCurrentThreadID) (void);
-
-
- C++ casts like
SDL_ThreadID tid = SDL_ThreadID(id);
- C++ casts like
-
-
-
- For C++ casts, just replace
SDL_ThreadID(id)with either a C-style cast
- For C++ casts, just replace
-
- (
(SDL_ThreadID)id) or one of the other C++ cast types like
- (
-
static_cast<SDL_ThreadID>(id).
-
-
- For the (hopefully rare) case of function pointers returning SDL_ThreadID,
-
- or any other legit case where
SDL_ThreadIDis followed by(that can’t be
- or any other legit case where
-
- easily avoided by using slightly different syntax, you can
#undef SDL_ThreadID
- easily avoided by using slightly different syntax, you can
-
- before your code using it to get rid of this define causing the compiler error.
-
-
- If you’re using
SDL_ENABLE_OLD_NAMESto support both SDL2 and SDL3 with
- If you’re using
-
- the same code, consider adding:
-
-
-
-
- #if SDL_MAJOR_VERSION == 2
-
- #define SDL_GetCurrentThreadID() SDL_ThreadID()
-
- #endif
-
-
-
-
- and using
SDL_GetCurrentThreadID()in your code, even if you otherwise use
- and using
-
- the SDL2 names.
-
-
- The gain of catching the bugs caused by accidentally using
SDL_ThreadID()
- The gain of catching the bugs caused by accidentally using
-
- when
SDL_GetCurrentThreadID()was intended hopefully outweight the annoyances
- when
-
- caused by this in some rare cases.
- */
+#define SDL_ThreadID() SDL_ThreadID_renamed_SDL_GetCurrentThreadID
#endif /* SDL_oldnames_h_ */
diff --git a/src/dynapi/SDL_dynapi.c b/src/dynapi/SDL_dynapi.c
index fcbbbd6d612d0..0f9e767e6fda6 100644
— a/src/dynapi/SDL_dynapi.c
+++ b/src/dynapi/SDL_dynapi.c
@@ -55,6 +55,12 @@
#include <windows.h>
#endif
+#ifdef SDL_ThreadID
+/* prevent the SDL_ThreadID() define from SDL_oldnames.h from breaking
- function pointer definitions */
+#undef SDL_ThreadID
+#endif
/* This is the version of the dynamic API. This doesn’t match the SDL version
and should not change until there’s been a major revamp in API/ABI.
So 2.0.5 adds functions over 2.0.4? This number doesn’t change;