Commit 82ed00a3 authored by Michael Droettboom's avatar Michael Droettboom

Guard against infinite recursion in self-referential data structures

parent 2e23079a
......@@ -108,8 +108,11 @@ is_type_name(PyObject* x, const char* name)
return result;
}
int
_python2js_cache(PyObject* x, PyObject* map, PyObject* pyparent, int jsparent);
static int
_python2js(PyObject* x)
_python2js(PyObject* x, PyObject* map)
{
if (x == Py_None) {
return hiwire_undefined();
......@@ -166,7 +169,7 @@ _python2js(PyObject* x)
Py_INCREF(x);
return pyproxy_new((int)x);
}
int jsitem = _python2js(pyitem);
int jsitem = _python2js_cache(pyitem, map, x, jsarray);
if (jsitem == -1) {
Py_DECREF(pyitem);
hiwire_decref(jsarray);
......@@ -182,12 +185,12 @@ _python2js(PyObject* x)
PyObject *pykey, *pyval;
Py_ssize_t pos = 0;
while (PyDict_Next(x, &pos, &pykey, &pyval)) {
int jskey = _python2js(pykey);
int jskey = _python2js_cache(pykey, map, x, jsdict);
if (jskey == -1) {
hiwire_decref(jsdict);
return -1;
}
int jsval = _python2js(pyval);
int jsval = _python2js_cache(pyval, map, NULL, 0);
if (jsval == -1) {
hiwire_decref(jskey);
hiwire_decref(jsdict);
......@@ -204,10 +207,43 @@ _python2js(PyObject* x)
}
}
int
_python2js_cache(PyObject* x, PyObject* map, PyObject* pyparent, int jsparent)
{
if (pyparent) {
PyObject* pyparentid = PyLong_FromSize_t((size_t)pyparent);
PyObject* jsparentid = PyLong_FromLong(jsparent);
if (PyDict_SetItem(map, pyparentid, jsparentid)) {
Py_DECREF(pyparentid);
Py_DECREF(jsparentid);
return -1;
}
Py_DECREF(pyparentid);
Py_DECREF(jsparentid);
}
PyObject* id = PyLong_FromSize_t((size_t)x);
PyObject* val = PyDict_GetItem(map, id);
int result;
if (val) {
result = PyLong_AsLong(val);
hiwire_incref(result);
Py_DECREF(val);
/* No need to check for result == -1, because that's the same */
/* value we use here to indicate error */
} else {
result = _python2js(x, map);
}
Py_DECREF(id);
return result;
}
int
python2js(PyObject* x)
{
int result = _python2js(x);
PyObject* map = PyDict_New();
int result = _python2js_cache(x, map, NULL, 0);
Py_DECREF(map);
if (result == -1) {
return pythonexc2js();
}
......
......@@ -406,3 +406,23 @@ def test_version_info(selenium):
version_js_str = selenium.run_js("return pyodide.version()")
version_js = LooseVersion(version_js_str)
assert version_py == version_js
def test_recursive_list(selenium):
selenium.run(
"""
x = []
x.append(x)
"""
)
selenium.run_js("x = pyodide.pyimport('x')")
def test_recursive_dict(selenium):
selenium.run(
"""
x = {}
x[0] = x
"""
)
selenium.run_js("x = pyodide.pyimport('x')")
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment