--- JSON-XS/XS.xs 2016/02/26 21:46:45 1.127 +++ JSON-XS/XS.xs 2017/08/17 01:42:20 1.131 @@ -8,6 +8,7 @@ #include #include #include +#include #if defined(__BORLANDC__) || defined(_MSC_VER) # define snprintf _snprintf // C compilers have this in stdio.h @@ -156,6 +157,31 @@ } } +/* adds two STRLENs together, slow, and with paranoia */ +STRLEN +strlen_sum (STRLEN l1, STRLEN l2) +{ + size_t sum = l1 + l2; + + if (sum < (size_t)l2 || sum != (size_t)(STRLEN)sum) + croak ("JSON::XS: string size overflow"); + + return sum; +} + +/* similar to SvGROW, but somewhat safer and guarantees exponential realloc strategy */ +static char * +json_sv_grow (SV *sv, size_t len1, size_t len2) +{ + len1 = strlen_sum (len1, len2); + len1 = strlen_sum (len1, len1 >> 1); + + if (len1 > 4096 - 24) + len1 = (len1 | 4095) - 24; + + return SvGROW (sv, len1); +} + // decode an utf-8 character and return it, or (UV)-1 in // case of an error. // we special-case "safe" characters from U+80 .. U+7FF, @@ -320,7 +346,6 @@ return 1; else if (*pv == '0') return 0; - } return -1; @@ -335,11 +360,14 @@ scalar = SvRV (scalar); - if (SvSTASH (scalar) == bool_stash) - return 1; + if (SvTYPE (scalar) >= SVt_PVMG) + { + if (SvSTASH (scalar) == bool_stash) + return 1; - if (!SvOBJECT (scalar) && ref_bool_type (scalar) >= 0) - return 1; + if (!SvOBJECT (scalar) && ref_bool_type (scalar) >= 0) + return 1; + } return 0; } @@ -361,12 +389,12 @@ INLINE void need (enc_t *enc, STRLEN len) { - if (expect_false (enc->cur + len >= enc->end)) + if (expect_false ((uintptr_t)(enc->end - enc->cur) < len)) { STRLEN cur = enc->cur - (char *)SvPVX (enc->sv); - SvGROW (enc->sv, cur + (len < (cur >> 2) ? cur >> 2 : len) + 1); - enc->cur = SvPVX (enc->sv) + cur; - enc->end = SvPVX (enc->sv) + SvLEN (enc->sv) - 1; + char *buf = json_sv_grow (enc->sv, cur, len); + enc->cur = buf + cur; + enc->end = buf + SvLEN (enc->sv) - 1; } } @@ -392,13 +420,13 @@ { if (expect_false (ch == '"')) // but with slow exceptions { - need (enc, len += 1); + need (enc, len + 1); *enc->cur++ = '\\'; *enc->cur++ = '"'; } else if (expect_false (ch == '\\')) { - need (enc, len += 1); + need (enc, len + 1); *enc->cur++ = '\\'; *enc->cur++ = '\\'; } @@ -411,11 +439,11 @@ { switch (ch) { - case '\010': need (enc, len += 1); *enc->cur++ = '\\'; *enc->cur++ = 'b'; ++str; break; - case '\011': need (enc, len += 1); *enc->cur++ = '\\'; *enc->cur++ = 't'; ++str; break; - case '\012': need (enc, len += 1); *enc->cur++ = '\\'; *enc->cur++ = 'n'; ++str; break; - case '\014': need (enc, len += 1); *enc->cur++ = '\\'; *enc->cur++ = 'f'; ++str; break; - case '\015': need (enc, len += 1); *enc->cur++ = '\\'; *enc->cur++ = 'r'; ++str; break; + case '\010': need (enc, len + 1); *enc->cur++ = '\\'; *enc->cur++ = 'b'; ++str; break; + case '\011': need (enc, len + 1); *enc->cur++ = '\\'; *enc->cur++ = 't'; ++str; break; + case '\012': need (enc, len + 1); *enc->cur++ = '\\'; *enc->cur++ = 'n'; ++str; break; + case '\014': need (enc, len + 1); *enc->cur++ = '\\'; *enc->cur++ = 'f'; ++str; break; + case '\015': need (enc, len + 1); *enc->cur++ = '\\'; *enc->cur++ = 'r'; ++str; break; default: { @@ -441,7 +469,7 @@ if (uch >= 0x110000UL) croak ("out of range codepoint (0x%lx) encountered, unrepresentable in JSON", (unsigned long)uch); - need (enc, len += 11); + need (enc, len + 11); sprintf (enc->cur, "\\u%04x\\u%04x", (int)((uch - 0x10000) / 0x400 + 0xD800), (int)((uch - 0x10000) % 0x400 + 0xDC00)); @@ -449,7 +477,7 @@ } else { - need (enc, len += 5); + need (enc, len + 5); *enc->cur++ = '\\'; *enc->cur++ = 'u'; *enc->cur++ = PL_hexdigit [ uch >> 12 ]; @@ -467,7 +495,7 @@ } else if (is_utf8) { - need (enc, len += clen); + need (enc, len + clen); do { *enc->cur++ = *str++; @@ -476,7 +504,7 @@ } else { - need (enc, len += UTF8_MAXBYTES - 1); // never more than 11 bytes needed + need (enc, len + UTF8_MAXBYTES - 1); // never more than 11 bytes needed enc->cur = encode_utf8 (enc->cur, uch); ++str; } @@ -1167,8 +1195,8 @@ { STRLEN cur = SvCUR (sv); - if (SvLEN (sv) <= cur + len) - SvGROW (sv, cur + (len < (cur >> 2) ? cur >> 2 : len) + 1); + if (SvLEN (sv) - cur <= len) + json_sv_grow (sv, cur, len); memcpy (SvPVX (sv) + SvCUR (sv), buf, len); SvCUR_set (sv, SvCUR (sv) + len); @@ -1689,7 +1717,7 @@ } static SV * -decode_json (SV *string, JSON *json, char **offset_return) +decode_json (SV *string, JSON *json, STRLEN *offset_return) { dec_t dec; SV *sv; @@ -1752,9 +1780,8 @@ sv = decode_sv (&dec); if (offset_return) - *offset_return = dec.cur; - - if (!(offset_return || !sv)) + *offset_return = dec.cur - SvPVX (string); + else if (sv) { // check for trailing garbage decode_ws (&dec); @@ -2111,11 +2138,11 @@ PPCODE: { SV *sv; - char *offset; + STRLEN offset; PUTBACK; sv = decode_json (jsonstr, self, &offset); SPAGAIN; EXTEND (SP, 2); PUSHs (sv); - PUSHs (sv_2mortal (newSVuv (ptr_to_index (jsonstr, offset)))); + PUSHs (sv_2mortal (newSVuv (ptr_to_index (jsonstr, SvPV_nolen (jsonstr) + offset)))); } void incr_parse (JSON *self, SV *jsonstr = 0) @@ -2159,8 +2186,8 @@ const char *str = SvPV (jsonstr, len); STRLEN cur = SvCUR (self->incr_text); - if (SvLEN (self->incr_text) <= cur + len) - SvGROW (self->incr_text, cur + (len < (cur >> 2) ? cur >> 2 : len) + 1); + if (SvLEN (self->incr_text) - cur <= len) + json_sv_grow (self->incr_text, cur, len); Move (str, SvEND (self->incr_text), len, char); SvCUR_set (self->incr_text, SvCUR (self->incr_text) + len); @@ -2172,7 +2199,7 @@ do { SV *sv; - char *offset; + STRLEN offset; if (!INCR_DONE (self)) { @@ -2198,11 +2225,11 @@ PUTBACK; sv = decode_json (self->incr_text, self, &offset); SPAGAIN; XPUSHs (sv); - self->incr_pos -= offset - SvPVX (self->incr_text); + self->incr_pos -= offset; self->incr_nest = 0; self->incr_mode = 0; - sv_chop (self->incr_text, offset); + sv_chop (self->incr_text, SvPVX (self->incr_text) + offset); } while (GIMME_V == G_ARRAY); }