--- JSON-XS/XS.xs 2008/03/26 01:40:43 1.81 +++ JSON-XS/XS.xs 2008/04/05 18:15:46 1.85 @@ -33,18 +33,10 @@ #define F_ALLOW_BLESSED 0x00000400UL #define F_CONV_BLESSED 0x00000800UL #define F_RELAXED 0x00001000UL - -#define F_MAXDEPTH 0xf8000000UL -#define S_MAXDEPTH 27 -#define F_MAXSIZE 0x01f00000UL -#define S_MAXSIZE 20 +#define F_ALLOW_UNKNOWN 0x00002000UL #define F_HOOK 0x00080000UL // some hooks exist, so slow-path processing -#define DEC_DEPTH(flags) (1UL << ((flags & F_MAXDEPTH) >> S_MAXDEPTH)) -#define DEC_SIZE(flags) (1UL << ((flags & F_MAXSIZE ) >> S_MAXSIZE )) - #define F_PRETTY F_INDENT | F_SPACE_BEFORE | F_SPACE_AFTER -#define F_DEFAULT (9UL << S_MAXDEPTH) #define INIT_SIZE 32 // initial scalar size to be allocated #define INDENT_STEP 3 // spaces per indentation level @@ -69,6 +61,8 @@ ((unsigned type)((unsigned type)(val) - (unsigned type)(beg)) \ <= (unsigned type)((unsigned type)(end) - (unsigned type)(beg))) +#define ERR_NESTING_EXCEEDED "json text or perl structure exceeds maximum nesting level (max_depth set too low?)" + #ifdef USE_ITHREADS # define JSON_SLOW 1 # define JSON_STASH (json_stash ? json_stash : gv_stashpv ("JSON::XS", 1)) @@ -91,19 +85,40 @@ typedef struct { U32 flags; + U32 max_depth; + STRLEN max_size; + SV *cb_object; HV *cb_sk_object; // for the incremental parser SV *incr_text; // the source text so far STRLEN incr_pos; // the current offset into the text - int incr_nest; // {[]}-nesting level - int incr_mode; + unsigned char incr_nest; // {[]}-nesting level + unsigned char incr_mode; } JSON; +INLINE void +json_init (JSON *json) +{ + Zero (json, 1, JSON); + json->max_depth = 512; +} + ///////////////////////////////////////////////////////////////////////////// // utility functions +INLINE SV * +get_bool (const char *name) +{ + SV *sv = get_sv (name, 1); + + SvREADONLY_on (sv); + SvREADONLY_on (SvRV (sv)); + + return sv; +} + INLINE void shrink (SV *sv) { @@ -172,7 +187,6 @@ SV *sv; // result scalar JSON json; U32 indent; // indentation level - U32 maxdepth; // max. indentation/recursion level UV limit; // escape character values >= this value when encoding } enc_t; @@ -355,8 +369,8 @@ { int i, len = av_len (av); - if (enc->indent >= enc->maxdepth) - croak ("data structure too deep (hit recursion limit)"); + if (enc->indent >= enc->json.max_depth) + croak (ERR_NESTING_EXCEEDED); encode_ch (enc, '['); @@ -441,8 +455,8 @@ { HE *he; - if (enc->indent >= enc->maxdepth) - croak ("data structure too deep (hit recursion limit)"); + if (enc->indent >= enc->json.max_depth) + croak (ERR_NESTING_EXCEEDED); encode_ch (enc, '{'); @@ -633,10 +647,14 @@ encode_str (enc, "true", 4, 0); else if (len == 1 && *pv == '0') encode_str (enc, "false", 5, 0); + else if (enc->json.flags & F_ALLOW_UNKNOWN) + encode_str (enc, "null", 4, 0); else croak ("cannot encode reference to scalar '%s' unless the scalar is 0 or 1", SvPV_nolen (sv_2mortal (newRV_inc (sv)))); } + else if (enc->json.flags & F_ALLOW_UNKNOWN) + encode_str (enc, "null", 4, 0); else croak ("encountered %s, but JSON can only represent references to arrays or hashes", SvPV_nolen (sv_2mortal (newRV_inc (sv)))); @@ -708,7 +726,7 @@ } else if (SvROK (sv)) encode_rv (enc, SvRV (sv)); - else if (!SvOK (sv)) + else if (!SvOK (sv) || enc->json.flags & F_ALLOW_UNKNOWN) encode_str (enc, "null", 4, 0); else croak ("encountered perl type (%s,0x%x) that JSON cannot handle, you might want to report this", @@ -728,7 +746,6 @@ enc.cur = SvPVX (enc.sv); enc.end = SvEND (enc.sv); enc.indent = 0; - enc.maxdepth = DEC_DEPTH (enc.json.flags); enc.limit = enc.json.flags & F_ASCII ? 0x000080UL : enc.json.flags & F_LATIN1 ? 0x000100UL : 0x110000UL; @@ -805,7 +822,7 @@ ++dec->cur; \ SE -#define DEC_INC_DEPTH if (++dec->depth > dec->maxdepth) ERR ("json datastructure exceeds maximum nesting level (set a higher max_depth)") +#define DEC_INC_DEPTH if (++dec->depth > dec->json.max_depth) ERR (ERR_NESTING_EXCEEDED) #define DEC_DEC_DEPTH --dec->depth static SV *decode_sv (dec_t *dec); @@ -1345,9 +1362,9 @@ { dec->cur += 4; #if JSON_SLOW - json_true = get_sv ("JSON::XS::true", 1); SvREADONLY_on (json_true); + json_true = get_bool ("JSON::XS::true"); #endif - return SvREFCNT_inc (json_true); + return newSVsv (json_true); } else ERR ("'true' expected"); @@ -1359,9 +1376,9 @@ { dec->cur += 5; #if JSON_SLOW - json_false = get_sv ("JSON::XS::false", 1); SvREADONLY_on (json_false); + json_false = get_bool ("JSON::XS::false"); #endif - return SvREFCNT_inc (json_false); + return newSVsv (json_false); } else ERR ("'false' expected"); @@ -1398,9 +1415,9 @@ SvGETMAGIC (string); SvUPGRADE (string, SVt_PV); - if (json->flags & F_MAXSIZE && SvCUR (string) > DEC_SIZE (json->flags)) + if (SvCUR (string) > json->max_size && json->max_size) croak ("attempted decode of JSON text of %lu bytes size, but max_size is set to %lu", - (unsigned long)SvCUR (string), (unsigned long)DEC_SIZE (json->flags)); + (unsigned long)SvCUR (string), (unsigned long)json->max_size); if (json->flags & F_UTF8) sv_utf8_downgrade (string, 0); @@ -1409,12 +1426,11 @@ SvGROW (string, SvCUR (string) + 1); // should basically be a NOP - dec.json = *json; - dec.cur = SvPVX (string); - dec.end = SvEND (string); - dec.err = 0; - dec.depth = 0; - dec.maxdepth = DEC_DEPTH (dec.json.flags); + dec.json = *json; + dec.cur = SvPVX (string); + dec.end = SvEND (string); + dec.err = 0; + dec.depth = 0; if (dec.json.cb_object || dec.json.cb_sk_object) dec.json.flags |= F_HOOK; @@ -1570,7 +1586,8 @@ case '[': case '{': - ++self->incr_nest; + if (++self->incr_nest > self->max_depth) + croak (ERR_NESTING_EXCEEDED); break; case ']': @@ -1609,8 +1626,8 @@ json_stash = gv_stashpv ("JSON::XS" , 1); json_boolean_stash = gv_stashpv ("JSON::XS::Boolean", 1); - json_true = get_sv ("JSON::XS::true" , 1); SvREADONLY_on (json_true ); - json_false = get_sv ("JSON::XS::false", 1); SvREADONLY_on (json_false); + json_true = get_bool ("JSON::XS::true"); + json_false = get_bool ("JSON::XS::false"); } PROTOTYPES: DISABLE @@ -1625,8 +1642,7 @@ { SV *pv = NEWSV (0, sizeof (JSON)); SvPOK_only (pv); - Zero (SvPVX (pv), 1, JSON); - ((JSON *)SvPVX (pv))->flags = F_DEFAULT; + json_init ((JSON *)SvPVX (pv)); XPUSHs (sv_2mortal (sv_bless ( newRV_noinc (pv), strEQ (klass, "JSON::XS") ? JSON_STASH : gv_stashpv (klass, 1) @@ -1648,6 +1664,7 @@ allow_blessed = F_ALLOW_BLESSED convert_blessed = F_CONV_BLESSED relaxed = F_RELAXED + allow_unknown = F_ALLOW_UNKNOWN PPCODE: { if (enable) @@ -1672,49 +1689,29 @@ get_allow_blessed = F_ALLOW_BLESSED get_convert_blessed = F_CONV_BLESSED get_relaxed = F_RELAXED + get_allow_unknown = F_ALLOW_UNKNOWN PPCODE: XPUSHs (boolSV (self->flags & ix)); -void max_depth (JSON *self, UV max_depth = 0x80000000UL) +void max_depth (JSON *self, U32 max_depth = 0x80000000UL) PPCODE: -{ - UV log2 = 0; - - if (max_depth > 0x80000000UL) max_depth = 0x80000000UL; - - while ((1UL << log2) < max_depth) - ++log2; - - self->flags = self->flags & ~F_MAXDEPTH | (log2 << S_MAXDEPTH); - + self->max_depth = max_depth; XPUSHs (ST (0)); -} U32 get_max_depth (JSON *self) CODE: - RETVAL = DEC_DEPTH (self->flags); + RETVAL = self->max_depth; OUTPUT: RETVAL -void max_size (JSON *self, UV max_size = 0) +void max_size (JSON *self, U32 max_size = 0) PPCODE: -{ - UV log2 = 0; - - if (max_size > 0x80000000UL) max_size = 0x80000000UL; - if (max_size == 1) max_size = 2; - - while ((1UL << log2) < max_size) - ++log2; - - self->flags = self->flags & ~F_MAXSIZE | (log2 << S_MAXSIZE); - + self->max_size = max_size; XPUSHs (ST (0)); -} int get_max_size (JSON *self) CODE: - RETVAL = DEC_SIZE (self->flags); + RETVAL = self->max_size; OUTPUT: RETVAL @@ -1800,10 +1797,17 @@ { STRLEN offset; - incr_parse (self); - if (!INCR_DONE (self)) - break; + { + incr_parse (self); + + if (self->incr_pos > self->max_size && self->max_size) + croak ("attempted decode of JSON text of %lu bytes size, but max_size is set to %lu", + (unsigned long)self->incr_pos, (unsigned long)self->max_size); + + if (!INCR_DONE (self)) + break; + } XPUSHs (decode_json (self->incr_text, self, &offset)); @@ -1820,7 +1824,7 @@ CODE: { if (self->incr_pos) - croak ("incr_text can only be called after a successful incr_parse call in scalar context"); + croak ("incr_text can not be called when the incremental parser already started parsing"); RETVAL = self->incr_text ? SvREFCNT_inc (self->incr_text) : &PL_sv_undef; } @@ -1853,7 +1857,9 @@ encode_json = F_UTF8 PPCODE: { - JSON json = { F_DEFAULT | ix }; + JSON json; + json_init (&json); + json.flags |= ix; XPUSHs (encode_json (scalar, &json)); } @@ -1863,7 +1869,9 @@ decode_json = F_UTF8 PPCODE: { - JSON json = { F_DEFAULT | ix }; + JSON json; + json_init (&json); + json.flags |= ix; XPUSHs (decode_json (jsonstr, &json, 0)); }