From 90e01040c526eb6379fb0955467e81ee81dde8bc Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 13 Sep 2024 17:00:15 -0700
Subject: [PATCH] Added thread-safe environment functions
Also marked the existing functions as unsafe, as they can cause crashes if used in multi-threaded applications.
As a bonus, since the new functions are hashtable based, hint environment lookups are much faster.
---
docs/README-vita.md | 6 +-
include/SDL3/SDL_stdinc.h | 210 ++++++++++++-
src/SDL.c | 2 +
src/SDL_hashtable.c | 5 +
src/SDL_hashtable.h | 1 +
src/SDL_hints.c | 8 +-
src/audio/SDL_audiodev.c | 2 +-
src/core/android/SDL_android.c | 3 +-
src/core/linux/SDL_ibus.c | 10 +-
src/core/linux/SDL_ime.c | 4 +-
src/core/linux/SDL_sandbox.c | 4 +-
src/dialog/unix/SDL_zenitydialog.c | 12 +-
src/dynapi/SDL_dynapi.c | 4 +-
src/dynapi/SDL_dynapi.sym | 14 +-
src/dynapi/SDL_dynapi_overrides.h | 14 +-
src/dynapi/SDL_dynapi_procs.h | 14 +-
src/filesystem/cocoa/SDL_sysfilesystem.m | 2 +-
src/filesystem/emscripten/SDL_sysfilesystem.c | 2 +-
src/filesystem/haiku/SDL_sysfilesystem.cc | 4 +-
src/filesystem/unix/SDL_sysfilesystem.c | 16 +-
src/gpu/vulkan/SDL_gpu_vulkan.c | 2 +-
src/haptic/SDL_haptic.c | 2 +-
src/locale/unix/SDL_syslocale.c | 4 +-
src/main/emscripten/SDL_sysmain_runapp.c | 2 +-
src/misc/unix/SDL_sysurl.c | 4 +-
src/process/posix/SDL_posixprocess.c | 19 +-
src/process/windows/SDL_windowsprocess.c | 6 +
src/stdlib/SDL_getenv.c | 278 +++++++++++++++++-
src/stdlib/SDL_iconv.c | 8 +-
src/test/SDL_test_memory.c | 2 +-
src/video/SDL_egl.c | 4 +-
src/video/wayland/SDL_waylandevents.c | 6 +-
src/video/wayland/SDL_waylandmessagebox.c | 4 +-
src/video/wayland/SDL_waylandmouse.c | 4 +-
src/video/wayland/SDL_waylandshmbuffer.c | 2 +-
src/video/wayland/SDL_waylandvideo.c | 4 +-
src/video/wayland/SDL_waylandwindow.c | 4 +-
src/video/x11/SDL_x11keyboard.c | 2 +-
src/video/x11/SDL_x11modes.c | 2 +-
test/childprocess.c | 36 +--
test/testatomic.c | 2 +-
test/testautomation_hints.c | 2 +-
test/testautomation_stdlib.c | 115 ++++----
test/testautomation_video.c | 4 +-
test/testerror.c | 2 +-
test/testprocess.c | 85 ++----
test/testsurround.c | 2 +-
test/testthread.c | 2 +-
test/testtimer.c | 2 +-
49 files changed, 696 insertions(+), 252 deletions(-)
diff --git a/docs/README-vita.md b/docs/README-vita.md
index 0a11cf806ba81..c222a14c86ed0 100644
--- a/docs/README-vita.md
+++ b/docs/README-vita.md
@@ -21,13 +21,13 @@ Notes
-----
* gles1/gles2 support and renderers are disabled by default and can be enabled by configuring with `-DVIDEO_VITA_PVR=ON`
These renderers support 720p and 1080i resolutions. These can be specified with:
- `SDL_setenv("VITA_RESOLUTION", "720", 1);` and `SDL_setenv("VITA_RESOLUTION", "1080", 1);`
+ `SDL_SetHint(SDL_HINT_VITA_RESOLUTION, "720");` and `SDL_SetHint(SDL_HINT_VITA_RESOLUTION, "1080");`
* Desktop GL 1.X and 2.X support and renderers are also disabled by default and also can be enabled with `-DVIDEO_VITA_PVR=ON` as long as gl4es4vita is present in your SDK.
- They support the same resolutions as the gles1/gles2 backends and require specifying `SDL_setenv("VITA_PVR_OGL", "1", 1);`
+ They support the same resolutions as the gles1/gles2 backends and require specifying `SDL_SetHint(SDL_HINT_VITA_PVR_OPENGL, "1");`
anytime before video subsystem initialization.
* gles2 support via PIB is disabled by default and can be enabled by configuring with `-DVIDEO_VITA_PIB=ON`
* By default SDL emits mouse events for touch events on every touchscreen.
Vita has two touchscreens, so it's recommended to use `SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");` and handle touch events instead.
Individual touchscreens can be disabled with:
- `SDL_setenv("VITA_DISABLE_TOUCH_FRONT", "1", 1);` and `SDL_setenv("VITA_DISABLE_TOUCH_BACK", "1", 1);`
+ `SDL_SetHint(SDL_HINT_VITA_ENABLE_FRONT_TOUCH, "0");` and `SDL_SetHint(SDL_HINT_VITA_ENABLE_BACK_TOUCH, "0");`
* Support for L2/R2/R3/R3 buttons, haptic feedback and gamepad led only available on PSTV, or when using external ds4 gamepad on vita.
diff --git a/include/SDL3/SDL_stdinc.h b/include/SDL3/SDL_stdinc.h
index aa6563ef890ff..21113ac6af8b5 100644
--- a/include/SDL3/SDL_stdinc.h
+++ b/include/SDL3/SDL_stdinc.h
@@ -978,9 +978,213 @@ extern SDL_DECLSPEC void SDLCALL SDL_aligned_free(void *mem);
*/
extern SDL_DECLSPEC int SDLCALL SDL_GetNumAllocations(void);
-extern SDL_DECLSPEC const char * SDLCALL SDL_getenv(const char *name);
-extern SDL_DECLSPEC int SDLCALL SDL_setenv(const char *name, const char *value, int overwrite);
-extern SDL_DECLSPEC int SDLCALL SDL_unsetenv(const char *name);
+/**
+ * A thread-safe set of environment variables
+ *
+ * \since This struct is available since SDL 3.0.0.
+ *
+ * \sa SDL_GetEnvironment
+ * \sa SDL_CleanupEnvironment
+ * \sa SDL_CreateEnvironment
+ * \sa SDL_GetEnvironmentVariable
+ * \sa SDL_GetEnvironmentVariables
+ * \sa SDL_SetEnvironmentVariable
+ * \sa SDL_UnsetEnvironmentVariable
+ * \sa SDL_DestroyEnvironment
+ */
+typedef struct SDL_Environment SDL_Environment;
+
+/**
+ * Get the process environment.
+ *
+ * This is initialized at application start and is not affected by setenv() and unsetenv() calls after that point. Use SDL_SetEnvironmentVariable() and SDL_UnsetEnvironmentVariable() if you want to modify this environment.
+ *
+ * \returns a pointer to the environment for the process or NULL on failure; call SDL_GetError()
+ * for more information.
+ *
+ * \threadsafety It is safe to call this function from any thread.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_CleanupEnvironment
+ * \sa SDL_GetEnvironmentVariable
+ * \sa SDL_GetEnvironmentVariables
+ * \sa SDL_SetEnvironmentVariable
+ * \sa SDL_UnsetEnvironmentVariable
+ */
+extern SDL_DECLSPEC SDL_Environment * SDLCALL SDL_GetEnvironment(void);
+
+/**
+ * Cleanup the process environment.
+ *
+ * This is called during SDL_Quit() to free the process environment. If SDL_GetEnvironment() is called afterwards, it will automatically create a new environment copied from the C runtime environment.
+ *
+ * \threadsafety This function is not thread-safe.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_GetEnvironment
+ */
+extern SDL_DECLSPEC void SDLCALL SDL_CleanupEnvironment(void);
+
+/**
+ * Create a set of environment variables
+ *
+ * \param empty SDL_TRUE to create an empty environment, SDL_FALSE to initialize it from the C runtime environment.
+ * \returns a pointer to the new environment or NULL on failure; call SDL_GetError()
+ * for more information.
+ *
+ * \threadsafety If `empty` is SDL_TRUE, it is safe to call this function from any thread, otherwise it is safe if no other threads are calling setenv() or unsetenv()
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_GetEnvironmentVariable
+ * \sa SDL_GetEnvironmentVariables
+ * \sa SDL_SetEnvironmentVariable
+ * \sa SDL_UnsetEnvironmentVariable
+ * \sa SDL_DestroyEnvironment
+ */
+extern SDL_DECLSPEC SDL_Environment * SDLCALL SDL_CreateEnvironment(SDL_bool empty);
+
+/**
+ * Get the value of a variable in the environment.
+ *
+ * \param env the environment to query.
+ * \param name the name of the variable to get.
+ * \returns a pointer to the value of the variable or NULL if it can't be found.
+ *
+ * \threadsafety It is safe to call this function from any thread.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_GetEnvironment
+ * \sa SDL_CreateEnvironment
+ * \sa SDL_GetEnvironmentVariables
+ * \sa SDL_SetEnvironmentVariable
+ * \sa SDL_UnsetEnvironmentVariable
+ */
+extern SDL_DECLSPEC const char * SDLCALL SDL_GetEnvironmentVariable(SDL_Environment *env, const char *name);
+
+/**
+ * Get all variables in the environment.
+ *
+ * \param env the environment to query.
+ * \returns a NULL terminated array of pointers to environment variables in the form "variable=value" or NULL on
+ * failure; call SDL_GetError() for more information. This is a
+ * single allocation that should be freed with SDL_free() when it is
+ * no longer needed.
+ *
+ * \threadsafety It is safe to call this function from any thread.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_GetEnvironment
+ * \sa SDL_CreateEnvironment
+ * \sa SDL_GetEnvironmentVariables
+ * \sa SDL_SetEnvironmentVariable
+ * \sa SDL_UnsetEnvironmentVariable
+ */
+extern SDL_DECLSPEC char ** SDLCALL SDL_GetEnvironmentVariables(SDL_Environment *env);
+
+/**
+ * Set the value of a variable in the environment.
+ *
+ * \param env the environment to modify.
+ * \param name the name of the variable to set.
+ * \param value the value of the variable to set.
+ * \param overwrite SDL_TRUE to overwrite the variable if it exists, SDL_FALSE to return success without setting the variable if it already exists.
+ * \returns SDL_TRUE on success or SDL_FALSE on failure; call SDL_GetError()
+ * for more information.
+ *
+ * \threadsafety It is safe to call this function from any thread.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_GetEnvironment
+ * \sa SDL_CreateEnvironment
+ * \sa SDL_GetEnvironmentVariable
+ * \sa SDL_GetEnvironmentVariables
+ * \sa SDL_UnsetEnvironmentVariable
+ */
+extern SDL_DECLSPEC SDL_bool SDLCALL SDL_SetEnvironmentVariable(SDL_Environment *env, const char *name, const char *value, SDL_bool overwrite);
+
+/**
+ * Clear a variable from the environment.
+ *
+ * \param env the environment to modify.
+ * \param name the name of the variable to unset.
+ * \returns SDL_TRUE on success or SDL_FALSE on failure; call SDL_GetError()
+ * for more information.
+ *
+ * \threadsafety It is safe to call this function from any thread.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_GetEnvironment
+ * \sa SDL_CreateEnvironment
+ * \sa SDL_GetEnvironmentVariable
+ * \sa SDL_GetEnvironmentVariables
+ * \sa SDL_SetEnvironmentVariable
+ * \sa SDL_UnsetEnvironmentVariable
+ */
+extern SDL_DECLSPEC SDL_bool SDLCALL SDL_UnsetEnvironmentVariable(SDL_Environment *env, const char *name);
+
+/**
+ * Destroy a set of environment variables.
+ *
+ * \param env the environment to destroy.
+ *
+ * \threadsafety It is safe to call this function from any thread, as long as the environment is no longer in use.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_CreateEnvironment
+ */
+extern SDL_DECLSPEC void SDLCALL SDL_DestroyEnvironment(SDL_Environment *env);
+
+/**
+ * Get the value of a variable in the environment.
+ *
+ * \param name the name of the variable to get.
+ * \returns a pointer to the value of the variable or NULL if it can't be found.
+ *
+ * \threadsafety This function is not thread safe, consider using SDL_GetEnvironmentVariable() instead.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_GetEnvironmentVariable
+ */
+extern SDL_DECLSPEC const char * SDLCALL SDL_getenv_unsafe(const char *name);
+
+/**
+ * Set the value of a variable in the environment.
+ *
+ * \param name the name of the variable to set.
+ * \param value the value of the variable to set.
+ * \param overwrite 1 to overwrite the variable if it exists, 0 to return success without setting the variable if it already exists.
+ * \returns 0 on success, -1 on error.
+ *
+ * \threadsafety This function is not thread safe, consider using SDL_SetEnvironmentVariable() instead.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_SetEnvironmentVariable
+ */
+extern SDL_DECLSPEC int SDLCALL SDL_setenv_unsafe(const char *name, const char *value, int overwrite);
+
+/**
+ * Clear a variable from the environment.
+ *
+ * \param name the name of the variable to unset.
+ * \returns 0 on success, -1 on error.
+ *
+ * \threadsafety This function is not thread safe, consider using SDL_UnsetEnvironmentVariable() instead..
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_UnsetEnvironmentVariable
+ */
+extern SDL_DECLSPEC int SDLCALL SDL_unsetenv_unsafe(const char *name);
typedef int (SDLCALL *SDL_CompareCallback)(const void *a, const void *b);
extern SDL_DECLSPEC void SDLCALL SDL_qsort(void *base, size_t nmemb, size_t size, SDL_CompareCallback compare);
diff --git a/src/SDL.c b/src/SDL.c
index e66fc34adf430..63c3347fb0e81 100644
--- a/src/SDL.c
+++ b/src/SDL.c
@@ -255,12 +255,14 @@ void SDL_InitMainThread(void)
SDL_InitLog();
SDL_InitProperties();
SDL_GetGlobalProperties();
+ SDL_GetEnvironment();
SDL_InitHints();
}
static void SDL_QuitMainThread(void)
{
SDL_QuitHints();
+ SDL_CleanupEnvironment();
SDL_QuitProperties();
SDL_QuitLog();
SDL_QuitFilesystem();
diff --git a/src/SDL_hashtable.c b/src/SDL_hashtable.c
index 168fe1e30b1e8..d233ce5949c2b 100644
--- a/src/SDL_hashtable.c
+++ b/src/SDL_hashtable.c
@@ -318,6 +318,11 @@ bool SDL_KeyMatchID(const void *a, const void *b, void *unused)
return false;
}
+void SDL_NukeFreeKey(const void *key, const void *value, void *unused)
+{
+ SDL_free((void *)key);
+}
+
void SDL_NukeFreeValue(const void *key, const void *value, void *unused)
{
SDL_free((void *)value);
diff --git a/src/SDL_hashtable.h b/src/SDL_hashtable.h
index c897e07c31066..55b6d53e86363 100644
--- a/src/SDL_hashtable.h
+++ b/src/SDL_hashtable.h
@@ -55,6 +55,7 @@ extern bool SDL_KeyMatchString(const void *a, const void *b, void *unused);
extern Uint32 SDL_HashID(const void *key, void *unused);
extern bool SDL_KeyMatchID(const void *a, const void *b, void *unused);
+extern void SDL_NukeFreeKey(const void *key, const void *value, void *unused);
extern void SDL_NukeFreeValue(const void *key, const void *value, void *unused);
#endif // SDL_hashtable_h_
diff --git a/src/SDL_hints.c b/src/SDL_hints.c
index 8dd9c551ccb09..a91877bbaad38 100644
--- a/src/SDL_hints.c
+++ b/src/SDL_hints.c
@@ -72,7 +72,7 @@ SDL_bool SDL_SetHintWithPriority(const char *name, const char *value, SDL_HintPr
return SDL_InvalidParamError("name");
}
- const char *env = SDL_getenv(name);
+ const char *env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), name);
if (env && (priority < SDL_HINT_OVERRIDE)) {
return SDL_SetError("An environment variable is taking priority");
}
@@ -126,7 +126,7 @@ SDL_bool SDL_ResetHint(const char *name)
return SDL_InvalidParamError("name");
}
- const char *env = SDL_getenv(name);
+ const char *env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), name);
const SDL_PropertiesID hints = GetHintProperties(false);
if (!hints) {
@@ -165,7 +165,7 @@ static void SDLCALL ResetHintsCallback(void *userdata, SDL_PropertiesID hints, c
return; // uh...okay.
}
- const char *env = SDL_getenv(name);
+ const char *env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), name);
if ((!env && hint->value) || (env && !hint->value) || (env && SDL_strcmp(env, hint->value) != 0)) {
SDL_HintWatch *entry = hint->callbacks;
while (entry) {
@@ -196,7 +196,7 @@ const char *SDL_GetHint(const char *name)
return NULL;
}
- const char *result = SDL_getenv(name);
+ const char *result = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), name);
const SDL_PropertiesID hints = GetHintProperties(false);
if (hints) {
diff --git a/src/audio/SDL_audiodev.c b/src/audio/SDL_audiodev.c
index f48a5b25d0bb5..f5dc4b20e95f3 100644
--- a/src/audio/SDL_audiodev.c
+++ b/src/audio/SDL_audiodev.c
@@ -87,7 +87,7 @@ static void SDL_EnumUnixAudioDevices_Internal(const bool recording, const bool c
}
// Figure out what our audio device is
- audiodev = SDL_getenv("AUDIODEV");
+ audiodev = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "AUDIODEV");
if (!audiodev) {
if (classic) {
audiodev = SDL_PATH_DEV_AUDIO;
diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c
index e24eaea13c73d..61baf17101f88 100644
--- a/src/core/android/SDL_android.c
+++ b/src/core/android/SDL_android.c
@@ -1524,7 +1524,8 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetenv)(
const char *utfname = (*env)->GetStringUTFChars(env, name, NULL);
const char *utfvalue = (*env)->GetStringUTFChars(env, value, NULL);
- SDL_setenv(utfname, utfvalue, 1);
+ // This is only called at startup, to initialize the environment
+ SDL_setenv_unsafe(utfname, utfvalue, 1);
(*env)->ReleaseStringUTFChars(env, name, utfname);
(*env)->ReleaseStringUTFChars(env, value, utfvalue);
diff --git a/src/core/linux/SDL_ibus.c b/src/core/linux/SDL_ibus.c
index dbbc3e1740e41..62daaf3a5fb0f 100644
--- a/src/core/linux/SDL_ibus.c
+++ b/src/core/linux/SDL_ibus.c
@@ -331,14 +331,14 @@ static char *IBus_GetDBusAddressFilename(void)
}
// Use this environment variable if it exists.
- addr = SDL_getenv("IBUS_ADDRESS");
+ addr = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "IBUS_ADDRESS");
if (addr && *addr) {
return SDL_strdup(addr);
}
/* Otherwise, we have to get the hostname, display, machine id, config dir
and look up the address from a filepath using all those bits, eek. */
- disp_env = SDL_getenv("DISPLAY");
+ disp_env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "DISPLAY");
if (!disp_env || !*disp_env) {
display = SDL_strdup(":0.0");
@@ -363,7 +363,7 @@ static char *IBus_GetDBusAddressFilename(void)
}
if (!*host) {
- const char *session = SDL_getenv("XDG_SESSION_TYPE");
+ const char *session = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_SESSION_TYPE");
if (session && SDL_strcmp(session, "wayland") == 0) {
host = "unix-wayland";
} else {
@@ -373,11 +373,11 @@ static char *IBus_GetDBusAddressFilename(void)
SDL_memset(config_dir, 0, sizeof(config_dir));
- conf_env = SDL_getenv("XDG_CONFIG_HOME");
+ conf_env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_CONFIG_HOME");
if (conf_env && *conf_env) {
SDL_strlcpy(config_dir, conf_env, sizeof(config_dir));
} else {
- const char *home_env = SDL_getenv("HOME");
+ const char *home_env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME");
if (!home_env || !*home_env) {
SDL_free(display);
return NULL;
diff --git a/src/core/linux/SDL_ime.c b/src/core/linux/SDL_ime.c
index a853618bb41c7..a371e658e1ca6 100644
--- a/src/core/linux/SDL_ime.c
+++ b/src/core/linux/SDL_ime.c
@@ -44,8 +44,8 @@ static void InitIME(void)
{
static bool inited = false;
#ifdef HAVE_FCITX
- const char *im_module = SDL_getenv("SDL_IM_MODULE");
- const char *xmodifiers = SDL_getenv("XMODIFIERS");
+ const char *im_module = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SDL_IM_MODULE");
+ const char *xmodifiers = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XMODIFIERS");
#endif
if (inited == true) {
diff --git a/src/core/linux/SDL_sandbox.c b/src/core/linux/SDL_sandbox.c
index 413148fc7b93b..797d36c1ef95e 100644
--- a/src/core/linux/SDL_sandbox.c
+++ b/src/core/linux/SDL_sandbox.c
@@ -33,7 +33,9 @@ SDL_Sandbox SDL_DetectSandbox(void)
/* For Snap, we check multiple variables because they might be set for
* unrelated reasons. This is the same thing WebKitGTK does. */
- if (SDL_getenv("SNAP") != NULL && SDL_getenv("SNAP_NAME") != NULL && SDL_getenv("SNAP_REVISION") != NULL) {
+ if (SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SNAP") != NULL &&
+ SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SNAP_NAME") != NULL &&
+ SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SNAP_REVISION") != NULL) {
return SDL_SANDBOX_SNAP;
}
diff --git a/src/dialog/unix/SDL_zenitydialog.c b/src/dialog/unix/SDL_zenitydialog.c
index 131352e7d9582..b77593aef2b18 100644
--- a/src/dialog/unix/SDL_zenitydialog.c
+++ b/src/dialog/unix/SDL_zenitydialog.c
@@ -229,12 +229,12 @@ static void run_zenity(zenityArgs* arg_struct)
/* Recent versions of Zenity have different exit codes, but picks up
different codes from the environment */
- SDL_setenv("ZENITY_OK", "0", 1);
- SDL_setenv("ZENITY_CANCEL", "1", 1);
- SDL_setenv("ZENITY_ESC", "1", 1);
- SDL_setenv("ZENITY_EXTRA", "2", 1);
- SDL_setenv("ZENITY_ERROR", "2", 1);
- SDL_setenv("ZENITY_TIMEOUT", "2", 1);
+ SDL_setenv_unsafe("ZENITY_OK", "0", 1);
+ SDL_setenv_unsafe("ZENITY_CANCEL", "1", 1);
+ SDL_setenv_unsafe("ZENITY_ESC", "1", 1);
+ SDL_setenv_unsafe("ZENITY_EXTRA", "2", 1);
+ SDL_setenv_unsafe("ZENITY_ERROR", "2", 1);
+ SDL_setenv_unsafe("ZENITY_TIMEOUT", "2", 1);
execv(args[0], args);
diff --git a/src/dynapi/SDL_dynapi.c b/src/dynapi/SDL_dynapi.c
index b67b6cb4eb0ac..f963c396dbb0f 100644
--- a/src/dynapi/SDL_dynapi.c
+++ b/src/dynapi/SDL_dynapi.c
@@ -351,7 +351,7 @@ static Sint32 initialize_jumptable(Uint32 apiver, void *table, Uint32 tablesize)
// Init our jump table first.
#if ENABLE_SDL_CALL_LOGGING
{
- const char *env = SDL_getenv_REAL("SDL_DYNAPI_LOG_CALLS");
+ const char *env = SDL_getenv_unsafe_REAL("SDL_DYNAPI_LOG_CALLS");
const SDL_bool log_calls = (env && SDL_atoi_REAL(env));
if (log_calls) {
#define SDL_DYNAPI_PROC(rc, fn, params, args, ret) jump_table.fn = fn##_LOGSDLCALLS;
@@ -461,7 +461,7 @@ extern SDL_NORETURN void SDL_ExitProcess(int exitcode);
static void SDL_InitDynamicAPILocked(void)
{
- const char *libname = SDL_getenv_REAL(SDL_DYNAMIC_API_ENVVAR);
+ const char *libname = SDL_getenv_unsafe_REAL(SDL_DYNAMIC_API_ENVVAR);
SDL_DYNAPI_ENTRYFN entry = NULL; // funcs from here by default.
SDL_bool use_internal = SDL_TRUE;
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index e44ed771adf98..21b51d2db3966 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -52,6 +52,7 @@ SDL3_0.0.0 {
SDL_BroadcastCondition;
SDL_CaptureMouse;
SDL_ClaimWindowForGPUDevice;
+ SDL_CleanupEnvironment;
SDL_CleanupTLS;
SDL_ClearAudioStream;
SDL_ClearClipboardData;
@@ -84,6 +85,7 @@ SDL3_0.0.0 {
SDL_CreateCondition;
SDL_CreateCursor;
SDL_CreateDirectory;
+ SDL_CreateEnvironment;
SDL_CreateGPUBuffer;
SDL_CreateGPUComputePipeline;
SDL_CreateGPUDevice;
@@ -125,6 +127,7 @@ SDL3_0.0.0 {
SDL_DestroyAudioStream;
SDL_DestroyCondition;
SDL_DestroyCursor;
+ SDL_DestroyEnvironment;
SDL_DestroyGPUDevice;
SDL_DestroyHapticEffect;
SDL_DestroyMutex;
@@ -276,6 +279,9 @@ SDL3_0.0.0 {
SDL_GetDisplayProperties;
SDL_GetDisplayUsableBounds;
SDL_GetDisplays;
+ SDL_GetEnvironment;
+ SDL_GetEnvironmentVariable;
+ SDL_GetEnvironmentVariables;
SDL_GetError;
SDL_GetEventFilter;
SDL_GetFloatProperty;
@@ -785,6 +791,7 @@ SDL3_0.0.0 {
SDL_SetClipboardData;
SDL_SetClipboardText;
SDL_SetCursor;
+ SDL_SetEnvironmentVariable;
SDL_SetError;
SDL_SetEventEnabled;
SDL_SetEventFilter;
@@ -933,6 +940,7 @@ SDL3_0.0.0 {
SDL_UnlockTexture;
SDL_UnmapGPUTransferBuffer;
SDL_UnregisterApp;
+ SDL_UnsetEnvironmentVariable;
SDL_UpdateGamepads;
SDL_UpdateHapticEffect;
SDL_UpdateJoysticks;
@@ -1020,7 +1028,7 @@ SDL3_0.0.0 {
SDL_fmod;
SDL_fmodf;
SDL_free;
- SDL_getenv;
+ SDL_getenv_unsafe;
SDL_hid_ble_scan;
SDL_hid_close;
SDL_hid_device_change_count;
@@ -1095,7 +1103,7 @@ SDL3_0.0.0 {
SDL_roundf;
SDL_scalbn;
SDL_scalbnf;
- SDL_setenv;
+ SDL_setenv_unsafe;
SDL_sin;
SDL_sinf;
SDL_snprintf;
@@ -1138,7 +1146,7 @@ SDL3_0.0.0 {
SDL_uitoa;
SDL_ulltoa;
SDL_ultoa;
- SDL_unsetenv;
+ SDL_unsetenv_unsafe;
SDL_utf8strlcpy;
SDL_utf8strlen;
SDL_utf8strnlen;
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 74a4b0bd881f1..7aa3c9bdc0d9a 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -77,6 +77,7 @@
#define SDL_BroadcastCondition SDL_BroadcastCondition_REAL
#define SDL_CaptureMouse SDL_CaptureMouse_REAL
#define SDL_ClaimWindowForGPUDevice SDL_ClaimWindowForGPUDevice_REAL
+#define SDL_CleanupEnvironment SDL_CleanupEnvironment_REAL
#define SDL_CleanupTLS SDL_CleanupTLS_REAL
#define SDL_ClearAudioStream SDL_ClearAudioStream_REAL
#define SDL_ClearClipboardData SDL_ClearClipboardData_REAL
@@ -109,6 +110,7 @@
#define SDL_CreateCondition SDL_CreateCondition_REAL
#define SDL_CreateCursor SDL_CreateCursor_REAL
#define SDL_CreateDirectory SDL_CreateDirectory_REAL
+#define SDL_CreateEnvironment SDL_CreateEnvironment_REAL
#define SDL_CreateGPUBuffer SDL_CreateGPUBuffer_REAL
#define SDL_CreateGPUComputePipeline SDL_CreateGPUComputePipeline_REAL
#define SDL_CreateGPUDevice SDL_CreateGPUDevice_REAL
@@ -150,6 +152,7 @@
#define SDL_DestroyAudioStream SDL_DestroyAudioStream_REAL
#define SDL_DestroyCondition SDL_DestroyCondition_REAL
#define SDL_DestroyCursor SDL_DestroyCursor_REAL
+#define SDL_DestroyEnvironment SDL_DestroyEnvironment_REAL
#define SDL_DestroyGPUDevice SDL_DestroyGPUDevice_REAL
#define SDL_DestroyHapticEffect SDL_DestroyHapticEffect_REAL
#define SDL_DestroyMutex SDL_DestroyMutex_REAL
@@ -301,6 +304,9 @@
#define SDL_GetDisplayProperties SDL_GetDisplayProperties_REAL
#define SDL_GetDisplayUsableBounds SDL_GetDisplayUsableBounds_REAL
#define SDL_GetDisplays SDL_GetDisplays_REAL
+#define SDL_GetEnvironment SDL_GetEnvironment_REAL
+#define SDL_GetEnvironmentVariable SDL_GetEnvironmentVariable_REAL
+#define SDL_GetEnvironmentVariables SDL_GetEnvironmentVariables_REAL
#define SDL_GetError SDL_GetError_REAL
#define SDL_GetEventFilter SDL_GetEventFilter_REAL
#define SDL_GetFloatProperty SDL_GetFloatProperty_REAL
@@ -810,6 +816,7 @@
#define SDL_SetClipboardData SDL_SetClipboardData_REAL
#define SDL_SetClipboardText SDL_SetClipboardText_REAL
#define SDL_SetCursor SDL_SetCursor_REAL
+#define SDL_SetEnvironmentVariable SDL_SetEnvironmentVariable_REAL
#define SDL_SetError SDL_SetError_REAL
#define SDL_SetEventEnabled SDL_SetEventEnabled_REAL
#define SDL_SetEventFilter SDL_SetEventFilter_REAL
@@ -958,6 +965,7 @@
#define SDL_UnlockTexture SDL_UnlockTexture_REAL
#define SDL_UnmapGPUTransferBuffer SDL_UnmapGPUTransferBuffer_REAL
#define SDL_UnregisterApp SDL_UnregisterApp_REAL
+#define SDL_UnsetEnvironmentVariable SDL_UnsetEnvironmentVariable_REAL
#define SDL_UpdateGamepads SDL_UpdateGamepads_REAL
#define SDL_UpdateHapticEffect SDL_UpdateHapticEffect_REAL
#define SDL_UpdateJoysticks SDL_UpdateJoysticks_REAL
@@ -1045,7 +1053,7 @@
#define SDL_fmod SDL_fmod_REAL
#define SDL_fmodf SDL_fmodf_REAL
#define SDL_free SDL_free_REAL
-#define SDL_getenv SDL_getenv_REAL
+#define SDL_getenv_unsafe SDL_getenv_unsafe_REAL
#define SDL_hid_ble_scan SDL_hid_ble_scan_REAL
#define SDL_hid_close SDL_hid_close_REAL
#define SDL_hid_device_change_count SDL_hid_device_change_count_REAL
@@ -1120,7 +1128,7 @@
#define SDL_roundf SDL_roundf_REAL
#define SDL_scalbn SDL_scalbn_REAL
#define SDL_scalbnf SDL_scalbnf_REAL
-#define SDL_setenv SDL_setenv_REAL
+#define SDL_setenv_unsafe SDL_setenv_unsafe_REAL
#define SDL_sin SDL_sin_REAL
#define SDL_sinf SDL_sinf_REAL
#define SDL_snprintf SDL_snprintf_REAL
@@ -1163,7 +1171,7 @@
#define SDL_uitoa SDL_uitoa_REAL
#define SDL_ulltoa SDL_ulltoa_REAL
#define SDL_ultoa SDL_ultoa_REAL
-#define SDL_unsetenv SDL_unsetenv_REAL
+#define SDL_unsetenv_unsafe SDL_unsetenv_unsafe_REAL
#define SDL_utf8strlcpy SDL_utf8strlcpy_REAL
#define SDL_utf8strlen SDL_utf8strlen_REAL
#define SDL_utf8strnlen SDL_utf8strnlen_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 29d5adc2c54f3..069d04ccc59d2 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -97,6 +97,7 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_BlitSurfaceUncheckedScaled,(SDL_Surface *a, const S
SDL_DYNAPI_PROC(void,SDL_BroadcastCondition,(SDL_Condition *a),(a),)
SDL_DYNAPI_PROC(SDL_bool,SDL_CaptureMouse,(SDL_bool a),(a),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_ClaimWindowForGPUDevice,(SDL_GPUDevice *a, SDL_Window *b),(a,b),return)
+SDL_DYNAPI_PROC(void,SDL_CleanupEnvironment,(void),(),)
SDL_DYNAPI_PROC(void,SDL_CleanupTLS,(void),(),)
SDL_DYNAPI_PROC(SDL_bool,SDL_ClearAudioStream,(SDL_AudioStream *a),(a),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_ClearClipboardData,(void),(),return)
@@ -129,6 +130,7 @@ SDL_DYNAPI_PROC(SDL_Cursor*,SDL_CreateColorCursor,(SDL_Surface *a, int b, int c)
SDL_DYNAPI_PROC(SDL_Condition*,SDL_CreateCondition,(void),(),return)
SDL_DYNAPI_PROC(SDL_Cursor*,SDL_CreateCursor,(const Uint8 *a, const Uint8 *b, int c, int d, int e, int f),(a,b,c,d,e,f),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_CreateDirectory,(const char *a),(a),return)
+SDL_DYNAPI_PROC(SDL_Environment*,SDL_CreateEnvironment,(SDL_bool a),(a),return)
SDL_DYNAPI_PROC(SDL_GPUBuffer*,SDL_CreateGPUBuffer,(SDL_GPUDevice *a, const SDL_GPUBufferCreateInfo* b),(a,b),return)
SDL_DYNAPI_PROC(SDL_GPUComputePipeline*,SDL_CreateGPUComputePipeline,(SDL_GPUDevice *a, const SDL_GPUComputePipelineCreateInfo *b),(a,b),return)
SDL_DYNAPI_PROC(SDL_GPUDevice*,SDL_CreateGPUDevice,(SDL_GPUShaderFormat a, SDL_bool b, const char *c),(a,b,c),return)
@@ -170,6 +172,7 @@ SDL_DYNAPI_PROC(void,SDL_DelayNS,(Uint64 a),(a),)
SDL_DYNAPI_PROC(void,SDL_DestroyAudioStream,(SDL_AudioStream *a),(a),)
SDL_DYNAPI_PROC(void,SDL_DestroyCondition,(SDL_Condition *a),(a),)
SDL_DYNAPI_PROC(void,SDL_DestroyCursor,(SDL_Cursor *a),(a),)
+SDL_DYNAPI_PROC(void,SDL_DestroyEnvironment,(SDL_Environment *a),(a),)
SDL_DYNAPI_PROC(void,SDL_DestroyGPUDevice,(SDL_GPUDevice *a),(a),)
SDL_DYNAPI_PROC(void,SDL_DestroyHapticEffect,(SDL_Haptic *a, int b),(a,b),)
SDL_DYNAPI_PROC(void,SDL_DestroyMutex,(SDL_Mutex *a),(a),)
@@ -321,6 +324,9 @@ SDL_DYNAPI_PROC(const char*,SDL_GetDisplayName,(SDL_DisplayID a),(a),return)
SDL_DYNAPI_PROC(SDL_PropertiesID,SDL_GetDisplayProperties,(SDL_DisplayID a),(a),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_GetDisplayUsableBounds,(SDL_DisplayID a, SDL_Rect *b),(a,b),return)
SDL_DYNAPI_PROC(SDL_DisplayID*,SDL_GetDisplays,(int *a),(a),return)
+SDL_DYNAPI_PROC(SDL_Environment*,SDL_GetEnvironment,(void),(),return)
+SDL_DYNAPI_PROC(const char*,SDL_GetEnvironmentVariable,(SDL_Environment *a, const char *b),(a,b),return)
+SDL_DYNAPI_PROC(char**,SDL_GetEnvironmentVariables,(SDL_Environment *a),(a),return)
SDL_DYNAPI_PROC(const char*,SDL_GetError,(void),(),return)
SDL_DYNAPI_PROC
(Patch may be truncated, please check the link at the top of this post.)