Browse Source

Safe use of snprintf() / vsnprintf() for Visual studio, and thread-safety fix

Two unrelated issues but touching the same are of code:
- For Visual Studio, we use the '#define snprint _snprintf' macro, but
 _snprinft isn't C99 compliant, and in particularly will not NUL terminate
 if the buffer isn't large enough. So 0 terminate explicitly
- In json_escape_str / json_object_int_to_json_string a static char[] buffer is
  used. This isn't thread-safe. Just use a plain char[]
pull/331/head
Even Rouault 8 years ago
parent
commit
17bc053d40
3 changed files with 11 additions and 5 deletions
  1. +5
    -2
      json_object.c
  2. +3
    -1
      json_util.c
  3. +3
    -2
      printbuf.c

+ 5
- 2
json_object.c View File

@@ -143,15 +143,16 @@ static int json_escape_str(struct printbuf *pb, const char *str, int len, int fl
default: default:
if(c < ' ') if(c < ' ')
{ {
char sbuf[7];
if(pos - start_offset > 0) if(pos - start_offset > 0)
printbuf_memappend(pb, printbuf_memappend(pb,
str + start_offset, str + start_offset,
pos - start_offset); pos - start_offset);
static char sbuf[7];
snprintf(sbuf, sizeof(sbuf), snprintf(sbuf, sizeof(sbuf),
"\\u00%c%c", "\\u00%c%c",
json_hex_chars[c >> 4], json_hex_chars[c >> 4],
json_hex_chars[c & 0xf]); json_hex_chars[c & 0xf]);
sbuf[sizeof(sbuf)-1] = '\0';
printbuf_memappend_fast(pb, sbuf, (int) sizeof(sbuf) - 1); printbuf_memappend_fast(pb, sbuf, (int) sizeof(sbuf) - 1);
start_offset = ++pos; start_offset = ++pos;
} else } else
@@ -589,8 +590,9 @@ static int json_object_int_to_json_string(struct json_object* jso,
int flags) int flags)
{ {
/* room for 19 digits, the sign char, and a null term */ /* room for 19 digits, the sign char, and a null term */
static char sbuf[21];
char sbuf[21];
snprintf(sbuf, sizeof(sbuf), "%" PRId64, jso->o.c_int64); snprintf(sbuf, sizeof(sbuf), "%" PRId64, jso->o.c_int64);
sbuf[sizeof(sbuf)-1] = '\0';
return printbuf_memappend (pb, sbuf, strlen(sbuf)); return printbuf_memappend (pb, sbuf, strlen(sbuf));
} }


@@ -749,6 +751,7 @@ static int json_object_double_to_json_string_format(struct json_object* jso,
NaN or Infinity as numeric values NaN or Infinity as numeric values
ECMA 262 section 9.8.1 defines ECMA 262 section 9.8.1 defines
how to handle these cases as strings */ how to handle these cases as strings */
buf[sizeof(buf)-1] = '\0';
if(isnan(jso->o.c_double)) if(isnan(jso->o.c_double))
size = snprintf(buf, sizeof(buf), "NaN"); size = snprintf(buf, sizeof(buf), "NaN");
else if(isinf(jso->o.c_double)) else if(isinf(jso->o.c_double))


+ 3
- 1
json_util.c View File

@@ -82,6 +82,7 @@ void _set_last_err(const char *err_fmt, ...)
va_start(ap, err_fmt); va_start(ap, err_fmt);
// Ignore (attempted) overruns from snprintf // Ignore (attempted) overruns from snprintf
(void)vsnprintf(_last_err, sizeof(_last_err), err_fmt, ap); (void)vsnprintf(_last_err, sizeof(_last_err), err_fmt, ap);
_last_err[sizeof(_last_err)-1] = '\0';
va_end(ap); va_end(ap);
} }


@@ -270,7 +271,8 @@ int json_parse_int64(const char *buf, int64_t *retval)
if (num64 == 0) // assume all sscanf impl's will parse -0 to 0 if (num64 == 0) // assume all sscanf impl's will parse -0 to 0
orig_has_neg = 0; // "-0" is the same as just plain "0" orig_has_neg = 0; // "-0" is the same as just plain "0"


snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64);
snprintf(buf_cmp, sizeof(buf_cmp), "%" PRId64, num64);
buf_cmp[sizeof(buf_cmp)-1] = '\0';
if (*buf_cmp_start == '-') if (*buf_cmp_start == '-')
{ {
recheck_has_neg = 1; recheck_has_neg = 1;


+ 3
- 2
printbuf.c View File

@@ -120,13 +120,14 @@ int sprintbuf(struct printbuf *p, const char *msg, ...)


/* user stack buffer first */ /* user stack buffer first */
va_start(ap, msg); va_start(ap, msg);
size = vsnprintf(buf, 128, msg, ap);
size = vsnprintf(buf, sizeof(buf), msg, ap);
buf[sizeof(buf)-1] = '\0';
va_end(ap); va_end(ap);
/* if string is greater than stack buffer, then use dynamic string /* if string is greater than stack buffer, then use dynamic string
with vasprintf. Note: some implementation of vsnprintf return -1 with vasprintf. Note: some implementation of vsnprintf return -1
if output is truncated whereas some return the number of bytes that if output is truncated whereas some return the number of bytes that
would have been written - this code handles both cases. */ would have been written - this code handles both cases. */
if(size == -1 || size > 127) {
if(size == -1 || size > (int)sizeof(buf)-1) {
va_start(ap, msg); va_start(ap, msg);
if((size = vasprintf(&t, msg, ap)) < 0) { va_end(ap); return -1; } if((size = vasprintf(&t, msg, ap)) < 0) { va_end(ap); return -1; }
va_end(ap); va_end(ap);


Loading…
Cancel
Save