mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-04-26 19:33:44 +02:00
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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -34,11 +34,17 @@ typedef enum
|
||||
SDL_ErrorCodeOutOfMemory,
|
||||
} SDL_ErrorCode;
|
||||
|
||||
typedef struct SDL_error
|
||||
typedef struct SDL_ErrorInfo
|
||||
{
|
||||
SDL_ErrorCode error;
|
||||
char *str;
|
||||
size_t len;
|
||||
} SDL_ErrorInfo;
|
||||
|
||||
typedef struct SDL_error
|
||||
{
|
||||
SDL_ErrorInfo info[2]; // there are two, so you can do SDL_SetError("%s", SDL_GetError()) without stomping the buffer.
|
||||
int current;
|
||||
SDL_realloc_func realloc_func;
|
||||
SDL_free_func free_func;
|
||||
} SDL_error;
|
||||
|
||||
@@ -262,9 +262,12 @@ void SDL_Generic_QuitTLSData(void)
|
||||
static SDL_error *SDL_GetStaticErrBuf(void)
|
||||
{
|
||||
static SDL_error SDL_global_error;
|
||||
static char SDL_global_error_str[128];
|
||||
SDL_global_error.str = SDL_global_error_str;
|
||||
SDL_global_error.len = sizeof(SDL_global_error_str);
|
||||
static char SDL_global_error_str1[128];
|
||||
static char SDL_global_error_str2[128];
|
||||
SDL_global_error.info[0].str = SDL_global_error_str1;
|
||||
SDL_global_error.info[0].len = sizeof(SDL_global_error_str1);
|
||||
SDL_global_error.info[1].str = SDL_global_error_str2;
|
||||
SDL_global_error.info[1].len = sizeof(SDL_global_error_str2);
|
||||
return &SDL_global_error;
|
||||
}
|
||||
|
||||
@@ -272,9 +275,11 @@ static SDL_error *SDL_GetStaticErrBuf(void)
|
||||
static void SDLCALL SDL_FreeErrBuf(void *data)
|
||||
{
|
||||
SDL_error *errbuf = (SDL_error *)data;
|
||||
|
||||
if (errbuf->str) {
|
||||
errbuf->free_func(errbuf->str);
|
||||
if (errbuf->info[0].str) {
|
||||
errbuf->free_func(errbuf->info[0].str);
|
||||
}
|
||||
if (errbuf->info[1].str) {
|
||||
errbuf->free_func(errbuf->info[1].str);
|
||||
}
|
||||
errbuf->free_func(errbuf);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user