Make SDL error string formatting deal with nasty corner cases.
authorRyan C. Gordon <icculus@icculus.org>
Tue, 24 Mar 2015 03:12:35 -0400
changeset 943092622f92bb8c
parent 9429 23d657bf9072
child 9431 a9c73f29a15e
Make SDL error string formatting deal with nasty corner cases.

We continued looping while maxlen > 0, but maxlen was unsigned, so an overflow
would make it a large number instead of negative. Fixed.

Some snprintf() implementations might return a negative value if there isn't
enough space, and we now check for that.

Don't overrun the SDL error message buffer, if snprintf() returned the number
of chars it wanted to write instead of the number it did.

snprintf is a portability mess, we should just never use the C runtime for it.

Fixes Bugzilla #2049.
src/SDL_error.c
     1.1 --- a/src/SDL_error.c	Tue Mar 24 02:48:16 2015 -0400
     1.2 +++ b/src/SDL_error.c	Tue Mar 24 03:12:35 2015 -0400
     1.3 @@ -120,7 +120,7 @@
     1.4     so that it supports internationalization and thread-safe errors.
     1.5  */
     1.6  static char *
     1.7 -SDL_GetErrorMsg(char *errstr, unsigned int maxlen)
     1.8 +SDL_GetErrorMsg(char *errstr, int maxlen)
     1.9  {
    1.10      SDL_error *error;
    1.11  
    1.12 @@ -163,37 +163,55 @@
    1.13                      len =
    1.14                          SDL_snprintf(msg, maxlen, tmp,
    1.15                                       error->args[argi++].value_i);
    1.16 -                    msg += len;
    1.17 -                    maxlen -= len;
    1.18 +                    if (len > 0) {
    1.19 +                        msg += len;
    1.20 +                        maxlen -= len;
    1.21 +                    }
    1.22                      break;
    1.23 +
    1.24                  case 'f':
    1.25                      len =
    1.26                          SDL_snprintf(msg, maxlen, tmp,
    1.27                                       error->args[argi++].value_f);
    1.28 -                    msg += len;
    1.29 -                    maxlen -= len;
    1.30 +                    if (len > 0) {
    1.31 +                        msg += len;
    1.32 +                        maxlen -= len;
    1.33 +                    }
    1.34                      break;
    1.35 +
    1.36                  case 'p':
    1.37                      len =
    1.38                          SDL_snprintf(msg, maxlen, tmp,
    1.39                                       error->args[argi++].value_ptr);
    1.40 -                    msg += len;
    1.41 -                    maxlen -= len;
    1.42 +                    if (len > 0) {
    1.43 +                        msg += len;
    1.44 +                        maxlen -= len;
    1.45 +                    }
    1.46                      break;
    1.47 +
    1.48                  case 's':
    1.49                      len =
    1.50                          SDL_snprintf(msg, maxlen, tmp,
    1.51                                       SDL_LookupString(error->args[argi++].
    1.52                                                        buf));
    1.53 -                    msg += len;
    1.54 -                    maxlen -= len;
    1.55 +                    if (len > 0) {
    1.56 +                        msg += len;
    1.57 +                        maxlen -= len;
    1.58 +                    }
    1.59                      break;
    1.60 +
    1.61                  }
    1.62              } else {
    1.63                  *msg++ = *fmt++;
    1.64                  maxlen -= 1;
    1.65              }
    1.66          }
    1.67 +
    1.68 +        /* slide back if we've overshot the end of our buffer. */
    1.69 +        if (maxlen < 0) {
    1.70 +            msg -= (-maxlen) + 1;
    1.71 +        }
    1.72 +
    1.73          *msg = 0;               /* NULL terminate the string */
    1.74      }
    1.75      return (errstr);