error: Alternate between two buffers in SDL_SetError.

This way you can always safely use SDL_GetError() in your formatted string:

```c
SDL_SetError("Couldn't open '%s': %s", filename, SDL_GetError());
```

This problem was hidden on platforms that use the dynamic API, because it
would format the new error string to a separate buffer first, to deal with
the varargs entry point.

Fixes #15456.
This commit is contained in:
Ryan C. Gordon
2026-04-25 14:56:51 -04:00
parent 30b0d2d8d0
commit 559d226fc6
3 changed files with 41 additions and 21 deletions

View File

@@ -43,22 +43,28 @@ bool SDL_SetErrorV(SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap)
if (fmt) {
int result;
SDL_error *error = SDL_GetErrBuf(true);
// use the other slot for the new error, so if this does
// SDL_SetError("%s", SDL_GetError()), we don't have a problem.
const int current = error->current ? 0 : 1;
SDL_ErrorInfo *errinfo = &error->info[current];
error->current = current;
errinfo->error = SDL_ErrorCodeGeneric;
va_list ap2;
error->error = SDL_ErrorCodeGeneric;
va_copy(ap2, ap);
result = SDL_vsnprintf(error->str, error->len, fmt, ap2);
result = SDL_vsnprintf(errinfo->str, errinfo->len, fmt, ap2);
va_end(ap2);
if (result >= 0 && (size_t)result >= error->len && error->realloc_func) {
if (result >= 0 && (size_t)result >= errinfo->len && error->realloc_func) {
size_t len = (size_t)result + 1;
char *str = (char *)error->realloc_func(error->str, len);
char *str = (char *)error->realloc_func(errinfo->str, len);
if (str) {
error->str = str;
error->len = len;
errinfo->str = str;
errinfo->len = len;
va_copy(ap2, ap);
(void)SDL_vsnprintf(error->str, error->len, fmt, ap2);
(void)SDL_vsnprintf(errinfo->str, errinfo->len, fmt, ap2);
va_end(ap2);
}
}
@@ -67,7 +73,7 @@ bool SDL_SetErrorV(SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap)
// Note that there are many recoverable errors that may happen internally and
// can be safely ignored if the public API doesn't return an error code.
#if 0
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "%s", error->str);
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "%s", errinfo->str);
#endif
}
@@ -82,9 +88,10 @@ const char *SDL_GetError(void)
return "";
}
switch (error->error) {
const SDL_ErrorInfo *errinfo = &error->info[error->current];
switch (errinfo->error) {
case SDL_ErrorCodeGeneric:
return error->str;
return errinfo->str;
case SDL_ErrorCodeOutOfMemory:
return "Out of memory";
default:
@@ -97,7 +104,8 @@ bool SDL_ClearError(void)
SDL_error *error = SDL_GetErrBuf(false);
if (error) {
error->error = SDL_ErrorCodeNone;
SDL_ErrorInfo *errinfo = &error->info[error->current];
errinfo->error = SDL_ErrorCodeNone;
}
return true;
}
@@ -107,7 +115,8 @@ bool SDL_OutOfMemory(void)
SDL_error *error = SDL_GetErrBuf(true);
if (error) {
error->error = SDL_ErrorCodeOutOfMemory;
SDL_ErrorInfo *errinfo = &error->info[error->current];
errinfo->error = SDL_ErrorCodeOutOfMemory;
}
return false;
}