Kaynağa Gözat

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.
Ryan C. Gordon 2 hafta önce
ebeveyn
işleme
559d226fc6
3 değiştirilmiş dosya ile 40 ekleme ve 20 silme
  1. 22 13
      src/SDL_error.c
  2. 7 1
      src/SDL_error_c.h
  3. 11 6
      src/thread/SDL_thread.c

+ 22 - 13
src/SDL_error.c

@@ -43,22 +43,28 @@ bool SDL_SetErrorV(SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap)
     if (fmt) {
     if (fmt) {
         int result;
         int result;
         SDL_error *error = SDL_GetErrBuf(true);
         SDL_error *error = SDL_GetErrBuf(true);
-        va_list ap2;
 
 
-        error->error = SDL_ErrorCodeGeneric;
+        // 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;
         va_copy(ap2, ap);
         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);
         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;
             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) {
             if (str) {
-                error->str = str;
-                error->len = len;
+                errinfo->str = str;
+                errinfo->len = len;
                 va_copy(ap2, ap);
                 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);
                 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
 // 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.
 // can be safely ignored if the public API doesn't return an error code.
 #if 0
 #if 0
-        SDL_LogError(SDL_LOG_CATEGORY_ERROR, "%s", error->str);
+        SDL_LogError(SDL_LOG_CATEGORY_ERROR, "%s", errinfo->str);
 #endif
 #endif
     }
     }
 
 
@@ -82,9 +88,10 @@ const char *SDL_GetError(void)
         return "";
         return "";
     }
     }
 
 
-    switch (error->error) {
+    const SDL_ErrorInfo *errinfo = &error->info[error->current];
+    switch (errinfo->error) {
     case SDL_ErrorCodeGeneric:
     case SDL_ErrorCodeGeneric:
-        return error->str;
+        return errinfo->str;
     case SDL_ErrorCodeOutOfMemory:
     case SDL_ErrorCodeOutOfMemory:
         return "Out of memory";
         return "Out of memory";
     default:
     default:
@@ -97,7 +104,8 @@ bool SDL_ClearError(void)
     SDL_error *error = SDL_GetErrBuf(false);
     SDL_error *error = SDL_GetErrBuf(false);
 
 
     if (error) {
     if (error) {
-        error->error = SDL_ErrorCodeNone;
+        SDL_ErrorInfo *errinfo = &error->info[error->current];
+        errinfo->error = SDL_ErrorCodeNone;
     }
     }
     return true;
     return true;
 }
 }
@@ -107,7 +115,8 @@ bool SDL_OutOfMemory(void)
     SDL_error *error = SDL_GetErrBuf(true);
     SDL_error *error = SDL_GetErrBuf(true);
 
 
     if (error) {
     if (error) {
-        error->error = SDL_ErrorCodeOutOfMemory;
+        SDL_ErrorInfo *errinfo = &error->info[error->current];
+        errinfo->error = SDL_ErrorCodeOutOfMemory;
     }
     }
     return false;
     return false;
 }
 }

+ 7 - 1
src/SDL_error_c.h

@@ -34,11 +34,17 @@ typedef enum
     SDL_ErrorCodeOutOfMemory,
     SDL_ErrorCodeOutOfMemory,
 } SDL_ErrorCode;
 } SDL_ErrorCode;
 
 
-typedef struct SDL_error
+typedef struct SDL_ErrorInfo
 {
 {
     SDL_ErrorCode error;
     SDL_ErrorCode error;
     char *str;
     char *str;
     size_t len;
     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_realloc_func realloc_func;
     SDL_free_func free_func;
     SDL_free_func free_func;
 } SDL_error;
 } SDL_error;

+ 11 - 6
src/thread/SDL_thread.c

@@ -262,9 +262,12 @@ void SDL_Generic_QuitTLSData(void)
 static SDL_error *SDL_GetStaticErrBuf(void)
 static SDL_error *SDL_GetStaticErrBuf(void)
 {
 {
     static SDL_error SDL_global_error;
     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;
     return &SDL_global_error;
 }
 }
 
 
@@ -272,9 +275,11 @@ static SDL_error *SDL_GetStaticErrBuf(void)
 static void SDLCALL SDL_FreeErrBuf(void *data)
 static void SDLCALL SDL_FreeErrBuf(void *data)
 {
 {
     SDL_error *errbuf = (SDL_error *)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);
     errbuf->free_func(errbuf);
 }
 }