--- JSON-XS/XS.xs 2010/01/19 00:31:13 1.104 +++ JSON-XS/XS.xs 2010/01/19 01:36:34 1.106 @@ -194,11 +194,17 @@ // scan a group of digits, and a trailing exponent static void -json_atof_scan1 (const char *s, NV *accum, int *expo, int postdp) +json_atof_scan1 (const char *s, NV *accum, int *expo, int postdp, int maxdepth) { UV uaccum = 0; int eaccum = 0; + // if we recurse too deep, skip all remaining digits + // to avoid a stack overflow attack + if (expect_false (--maxdepth <= 0)) + while (((U8)*s - '0') < 10) + ++s; + for (;;) { U8 dig = (U8)*s - '0'; @@ -208,7 +214,7 @@ if (dig == (U8)((U8)'.' - (U8)'0')) { ++s; - json_atof_scan1 (s, accum, expo, 1); + json_atof_scan1 (s, accum, expo, 1, maxdepth); } else if ((dig | ' ') == 'e' - '0') { @@ -244,15 +250,18 @@ if (uaccum >= (UV_MAX - 9) / 10) { if (postdp) *expo -= eaccum; - json_atof_scan1 (s, accum, expo, postdp); + json_atof_scan1 (s, accum, expo, postdp, maxdepth); if (postdp) *expo += eaccum; break; } } + // this relies greatly on the quality of the pow () + // implementation of the platform, but a good + // implementation is hard to beat. if (postdp) *expo -= eaccum; - *accum += uaccum * pow (10., *expo); + *accum += uaccum * Perl_pow (10., *expo); *expo += eaccum; } @@ -269,7 +278,8 @@ neg = 1; } - json_atof_scan1 (s, &accum, &expo, 0); + // a recursion depth of ten gives us >>500 bits + json_atof_scan1 (s, &accum, &expo, 0, 10); return neg ? -accum : accum; }