Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2fabb7c

Browse files
committed
Add a way of setting the maximum stack size.
1 parent 4bdcf8e commit 2fabb7c

File tree

4 files changed

+53
-2
lines changed

4 files changed

+53
-2
lines changed

‎module.c‎

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ typedef struct {
2121

2222
// The exception raised by this module.
2323
static PyObject *JSException = NULL;
24+
static PyObject *StackOverflow = NULL;
2425
// Converts a JSValue to a Python object.
2526
//
2627
// Takes ownership of the JSValue and will deallocate it (refcount reduced by 1).
@@ -210,7 +211,11 @@ static PyObject *quickjs_to_python(ContextData *context_obj, JSValue value) {
210211
JSValue exception = JS_GetException(context);
211212
JSValue error_string = JS_ToString(context, exception);
212213
const char *cstring = JS_ToCString(context, error_string);
213-
PyErr_Format(JSException, "%s", cstring);
214+
if (strstr(cstring, "stack overflow") != NULL) {
215+
PyErr_Format(StackOverflow, "%s", cstring);
216+
} else {
217+
PyErr_Format(JSException, "%s", cstring);
218+
}
214219
JS_FreeCString(context, cstring);
215220
JS_FreeValue(context, error_string);
216221
JS_FreeValue(context, exception);
@@ -349,6 +354,18 @@ static PyObject *context_set_time_limit(ContextData *self, PyObject *args) {
349354
Py_RETURN_NONE;
350355
}
351356

357+
// _quickjs.Context.set_max_stack_size
358+
//
359+
// Sets the max stack size in bytes.
360+
static PyObject *context_set_max_stack_size(ContextData *self, PyObject *args) {
361+
Py_ssize_t limit;
362+
if (!PyArg_ParseTuple(args, "n", &limit)) {
363+
return NULL;
364+
}
365+
JS_SetMaxStackSize(self->context, limit);
366+
Py_RETURN_NONE;
367+
}
368+
352369
// _quickjs.Context.memory
353370
//
354371
// Sets the CPU time limit of the context. This will be used in an interrupt handler.
@@ -420,6 +437,10 @@ static PyMethodDef context_methods[] = {
420437
(PyCFunction)context_set_time_limit,
421438
METH_VARARGS,
422439
"Sets the CPU time limit in seconds (C function clock() is used)."},
440+
{"set_max_stack_size",
441+
(PyCFunction)context_set_max_stack_size,
442+
METH_VARARGS,
443+
"Sets the maximum stack size in bytes. Default is 256kB."},
423444
{"memory", (PyCFunction)context_memory, METH_NOARGS, "Returns the memory usage as a dict."},
424445
{"gc", (PyCFunction)context_gc, METH_NOARGS, "Runs garbage collection."},
425446
{NULL} /* Sentinel */
@@ -468,11 +489,16 @@ PyMODINIT_FUNC PyInit__quickjs(void) {
468489
if (JSException == NULL) {
469490
return NULL;
470491
}
492+
StackOverflow = PyErr_NewException("_quickjs.StackOverflow", JSException, NULL);
493+
if (StackOverflow == NULL) {
494+
return NULL;
495+
}
471496

472497
Py_INCREF(&Context);
473498
PyModule_AddObject(module, "Context", (PyObject *)&Context);
474499
Py_INCREF(&Object);
475500
PyModule_AddObject(module, "Object", (PyObject *)&Object);
476501
PyModule_AddObject(module, "JSException", JSException);
502+
PyModule_AddObject(module, "StackOverflow", StackOverflow);
477503
return module;
478504
}

‎quickjs/__init__.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ def test():
1111
Context = _quickjs.Context
1212
Object = _quickjs.Object
1313
JSException = _quickjs.JSException
14+
StackOverflow = _quickjs.StackOverflow
1415

1516

1617
class Function:
@@ -32,6 +33,10 @@ def set_time_limit(self, limit):
3233
with self._lock:
3334
return self._context.set_time_limit(limit)
3435

36+
def set_max_stack_size(self, limit):
37+
with self._lock:
38+
return self._context.set_max_stack_size(limit)
39+
3540
def memory(self):
3641
with self._lock:
3742
return self._context.memory()

‎setup.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
# on computers where it is not installed.
2323
extra_link_args = ["-Wl,-Bstatic", "-lpthread"]
2424

25+
2526
def get_c_sources(include_headers=False):
2627
sources = ['module.c'] + glob.glob("third-party/*.c")
2728
if include_headers:
@@ -45,7 +46,7 @@ def get_c_sources(include_headers=False):
4546
author_email="petter.strandmark@gmail.com",
4647
name='quickjs',
4748
url='https://github.com/PetterS/quickjs',
48-
version='1.3.1',
49+
version='1.4.0',
4950
description='Wrapping the quickjs C library.',
5051
long_description=long_description,
5152
packages=["quickjs"],

‎test_quickjs.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,25 @@ def test_garbage_collection(self):
308308
f.gc()
309309
self.assertLessEqual(f.memory()["obj_count"], initial_count)
310310

311+
def test_deep_recursion(self):
312+
f = quickjs.Function(
313+
"f", """
314+
function f(v) {
315+
if (v <= 0) {
316+
return 0;
317+
} else {
318+
return 1 + f(v - 1);
319+
}
320+
}
321+
""")
322+
323+
self.assertEqual(f(100), 100)
324+
limit = 500
325+
with self.assertRaises(quickjs.StackOverflow):
326+
f(limit)
327+
f.set_max_stack_size(2000 * limit)
328+
self.assertEqual(f(limit), limit)
329+
311330

312331
class Strings(unittest.TestCase):
313332
def test_unicode(self):

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /