ibmruntimes / yieldable-json

Asynchronous JSON parser and stringify APIs that make use of generator patterns
Other
145 stars 22 forks source link

Not catchable "RangeError: Maximum callstack size exceeded" error #34

Open julienbeaussier opened 2 years ago

julienbeaussier commented 2 years ago

Hello,

We noticed parsing can fail with some very nested objects where the max call stack size is reached, which is kind of expected with a recursive approach. On my end, it start failing around 3500 depth of nesting.

However, it seems the error cannot be always caught by a try..catch, and handled correctly on our side.

Following is an example code that leads to a RangeError: Maximum Call Stack Exceeded error.

'use strict';

const yj = require('yieldable-json');

const count = 10000;
let objArray = new Array(count * 2 + 1);
for (let i = 0; i < count; i++) {
    objArray[i] = `{"foo${i}":`;
}
objArray[count] = '42';
for (let i = count + 1; i < 2 * count + 1; i++) {
    objArray[i] = '}';
}
const obj = objArray.join('');

try {
    yj.parseAsync(obj, null, 1, 20, (err, res) => {
        if (!err) {
            console.log('Success', res);
        } else {
            console.error('Error in callback', err);
        }
    });
} catch (e) {
    console.error('Try..Catch', e);
}

process.on('uncaughtException', (e) => {
    console.error('Uncaught', e);
});

And it's output:

Uncaught RangeError: Maximum call stack size exceeded
    at parseYield (/xxx/node_modules/yieldable-json/yieldable-parser.js:139:24)
    at parseYield (/xxx/node_modules/yieldable-json/yieldable-parser.js:191:26)
    at parseYield.next (<anonymous>)
    at parseYield (/xxx/node_modules/yieldable-json/yieldable-parser.js:196:37)
    at parseYield.next (<anonymous>)
    at parseYield (/xxx/node_modules/yieldable-json/yieldable-parser.js:196:37)
    at parseYield.next (<anonymous>)
    at parseYield (/xxx/node_modules/yieldable-json/yieldable-parser.js:196:37)
    at parseYield.next (<anonymous>)
    at parseYield (/xxx/node_modules/yieldable-json/yieldable-parser.js:196:37)

Keeping the recursive approach, a solution would be to fail gracefully after a given depth is reached, with for example a new ParseError('RangeError: Maximum call stack size exceeded').

If I have missed something that would have let me handle this issue properly, please let me know.

Thank you.