Closed elgow closed 3 years ago
Thanks for the report. That is weird and indeed looks like a bug. Will look into it at some point.
It has to do with how quickjs detects the current stack pointer in order to calculate the remaining stack. Somehow Python is in a very different place when evaluating an __init__
method.
If you write qjs.interp = quickjs.Context()
it works.
The Function
class runs everything in its own threadpool to get around QuickJS being so thread-hostile. I am told (via the mailing list) that this hostility will be relaxed in the future.
So the work-around is to use quikcjs.Function
or a similar method.
I added a test case so we can track this.
Thank you both for creating the Python binding for quickjs and for your very quick action on this issue.
Based on your analysis I tried some further experiments and what I found fits your conclusion
In [19]: class QJS(object):
...: def __init__(self, qjs=quickjs.Context()):
...: self.interp = qjs
...: self.interp.eval('var foo = "bar";')
...: def mc(self):
...: self.interp = quickjs.Context()
...:
In [20]: qjs = QJS()
In [21]: qjs.interp.eval('2+2')
---------------------------------------------------------------------------
StackOverflow Traceback (most recent call last)
<ipython-input-21-bc13b324733b> in <module>
----> 1 qjs.interp.eval('2+2')
StackOverflow: InternalError: stack overflow
In [22]: qjs = QJS(quickjs.Context())
In [23]: qjs.interp.eval('2+2')
Out[23]: 4
In [24]: qjs.mc()
In [25]: qjs.interp.eval('2+2')
---------------------------------------------------------------------------
StackOverflow Traceback (most recent call last)
<ipython-input-25-bc13b324733b> in <module>
----> 1 qjs.interp.eval('2+2')
StackOverflow: InternalError: stack overflow
So the gist of it seems to be that a quickjs.Context created when running in any method call on an object instance gets shortchanged on stack space while one created in the interpreter context is fine.
Also, creating the Context within a top-level function doesn't cause the problem:
In [35]: def mkq():
...: qjs = QJS(quickjs.Context())
...: print(f"> {qjs.interp.eval('2+2')}", flush=True)
...: qjs = QJS()
...: #print(f">> {qjs.interp.eval('2+2')}", flush=True)
...:
In [36]: mkq()
> 4
So it does seem to only afflict methods of a class instance. In the above example if the 2nd print statement is uncommented then you get a StackOverflow
It is a bit unorthodox, to be sure! Will update this issue if the situation changes.
Forgive me for being so vociferous in commenting, but I'm hoping it might help others who encounter this issue to understand and work around it.
I have to revise the last bit of the previous comment. Executing the eval() within the same context in which the quickjs.Context was created works, but any use outside that context fails. So the final test works because the qjs.interp.eval()
call inside of the mkq()
function is still in the context where quickjs.Context()
was called.
As long as you can set up your quickjs.Context, execute your Javascript, and get your result within a single function call or interpreter context then you're OK. This covers using quickjs.py to execute Javascript code for a single HTTP request handler, which is sufficient for my immediate purpose.
Thanks again for bringing quickjs to the Python world.
For some reason a quickjs
Context
held in an attribute of a Python class throws StackOverflow errors when itseval()
method is called. Here's an ipython session demonstrating:As you can see in the session, calling
get()
on the instance context works properly to return the value of the variablefoo
buteval()
, which should return the same value, fails. When the same is tried on aContext
that is not in an object instance it works properly .This is using Python 3.6.8 and quickjs 1.6.0.