"AssertionError: stack overflow" trying to push a complex JSON object with 10-level nested fields
javierfernandes opened this issue · comments
Hi all !
I run into what seems a limit of the stack size when trying to push a complex object that has a pretty nested structure. Fengari fails with this error
AssertionError: stack overflow
at Object.lua_pushstring (node_modules/fengari/src/lapi.js:259:5)
at Object.push (node_modules/fengari-interop/src/jslib.js:71:7)
at push (src/engine/vm/FengariBNEVM.js:394:15)
at Array.forEach (<anonymous>)
at Object.forEach [as _pushObject] (src/engine/vm/FengariBNEVM.js:393:22)
at Object._pushObject [as _push] (src/engine/vm/FengariBNEVM.js:367:12)
at _push (src/engine/vm/FengariBNEVM.js:395:12)
at Array.forEach (<anonymous>)
at Object.forEach [as _pushObject] (src/engine/vm/FengariBNEVM.js:393:22)
at Object._pushObject [as _push] (src/engine/vm/FengariBNEVM.js:367:12) thrown
I've tracked the code to all push_ methods which do this
api_check(L, L.top <= L.ci.top, "stack overflow");
I can see that L.ci.top
is always 21. And looking at the code I guess that it is some sort of max stack size (?) that I'm reaching. This seems to come from const LUA_MINSTACK = 20;
Here is a test to reproduce this
it('should push an objects with 10 level nested fields', () => {
expect(vm._getTop()).toBe(1)
vm._pushObject({
a: {
b: {
c: {
d: {
e: {
f: {
g: {
h: {
i: {
j: 'blah' // AT THIS LEVEL IT STARTS TO FAIL !
}
}
}
}
},
}
},
},
}
})
expect(vm._getTop()).toBe(2)
})
vm
is just a class that wraps all the fengari calls.
Here all the push methods just in case:
_pushObject(obj) {
this.lua.lua_newtable(this.L)
const sub_table_index = this._getTop()
Object.keys(obj).forEach(fieldName => {
interop.push(this.L, fieldName)
this._push(obj[fieldName])
this.lua.lua_settable(this.L, sub_table_index)
})
}
_push(value) {
if (Array.isArray(value)) {
this._pushArray(value)
} else if (isComplexObject(value)) {
this._pushObject(value)
} else {
this._pushValue(value)
}
},
_pushValue(value) {
interop.push(this.L, value)
},
_pushArray(array) {
this.lua.lua_newtable(this.L)
const sub_table_index = this._getTop()
array.forEach((e, i) => {
interop.push(this.L, i + 1)
this._push(e)
this.lua.lua_settable(this.L, sub_table_index)
})
},
Am I reaching a limit here ? If so, is there a way to extend it ? or maybe to do it in a way that it won't hit it, like a workaround ?
Or maybe I'm doing it wrong ?
Thanks in advance !
I think you just need some luaL_checkstack
calls at your point of recursion.
@daurnimator thanks !!!
That did the trick !
I didn't know one was supposed to manually make the stack grow to fit what you were going to do next. I'm not so used to working with stack :)
I will close this issue then. I think that it might still help some other like me in the future, since I searched for "stack overflow" without any luck in this repo.