Commit 81db3193 authored by Michael Droettboom's avatar Michael Droettboom Committed by GitHub

Merge pull request #74 from iodide-project/safer-eval

Safer parsing of expression at end of code block
parents c7140ccb 4a8e63c3
......@@ -48,7 +48,7 @@ main(int argc, char** argv)
if (js2python_init() || JsImport_init() || JsProxy_init() ||
pyimport_init() || pyproxy_init() || python2js_init() ||
runpython_init()) {
runpython_init_js() || runpython_init_py()) {
return 1;
}
......
......@@ -4,6 +4,7 @@ A library of helper utilities for connecting Python to the browser environment.
from js import XMLHttpRequest
import ast
import io
......@@ -17,4 +18,23 @@ def open_url(url):
return io.StringIO(req.response)
__all__ = ['open_url']
def eval_code(code, ns):
"""
Runs a string of code, the last part of which may be an expression.
"""
mod = ast.parse(code)
if isinstance(mod.body[-1], ast.Expr):
expr = ast.Expression(mod.body[-1].value)
del mod.body[-1]
else:
expr = None
if len(mod.body):
exec(compile(mod, '<exec>', mode='exec'), ns, ns)
if expr is not None:
return eval(compile(expr, '<eval>', mode='eval'), ns, ns)
else:
return None
__all__ = ['open_url', 'eval_code']
......@@ -9,79 +9,19 @@
extern PyObject* globals;
static int
is_whitespace(char x)
{
switch (x) {
case ' ':
case '\n':
case '\r':
case '\t':
return 1;
default:
return 0;
}
}
PyObject *eval_code;
int
_runPython(char* code)
{
char* last_line = code;
while (*last_line != 0) {
++last_line;
}
size_t length = last_line - code;
PyCompilerFlags cf;
cf.cf_flags = PyCF_SOURCE_IS_UTF8;
PyEval_MergeCompilerFlags(&cf);
if (length == 0) {
return hiwire_undefined();
}
// Find the last non-whitespace-only line since that will provide the result
// TODO: This way to find the last line will probably break in many ways
last_line--;
for (; last_line != code && is_whitespace(*last_line); last_line--) {
}
for (; last_line != code && *last_line != '\n'; last_line--) {
}
int do_eval_line = 1;
struct _node* co;
co = PyParser_SimpleParseStringFlags(last_line, Py_eval_input, cf.cf_flags);
if (co == NULL) {
do_eval_line = 0;
PyErr_Clear();
}
PyNode_Free(co);
PyObject* ret;
if (do_eval_line == 0 || last_line != code) {
if (do_eval_line) {
*last_line = 0;
last_line++;
}
ret = PyRun_StringFlags(code, Py_file_input, globals, globals, &cf);
if (ret == NULL) {
return pythonexc2js();
}
Py_DECREF(ret);
PyObject *py_code;
py_code = PyUnicode_FromString(code);
if (py_code == NULL) {
return pythonexc2js();
}
switch (do_eval_line) {
case 0:
Py_INCREF(Py_None);
ret = Py_None;
break;
case 1:
ret = PyRun_StringFlags(last_line, Py_eval_input, globals, globals, &cf);
break;
case 2:
ret = PyRun_StringFlags(last_line, Py_file_input, globals, globals, &cf);
break;
}
PyObject *ret = PyObject_CallFunctionObjArgs(
eval_code, py_code, globals, NULL);
if (ret == NULL) {
return pythonexc2js();
......@@ -92,7 +32,7 @@ _runPython(char* code)
return id;
}
EM_JS(int, runpython_init, (), {
EM_JS(int, runpython_init_js, (), {
Module.runPython = function(code)
{
var pycode = allocate(intArrayFromString(code), 'i8', ALLOC_NORMAL);
......@@ -105,3 +45,24 @@ EM_JS(int, runpython_init, (), {
return 0;
});
int runpython_init_py() {
PyObject *m = PyImport_ImportModule("pyodide");
if (m == NULL) {
return 1;
}
PyObject *d = PyModule_GetDict(m);
if (d == NULL) {
return 1;
}
eval_code = PyDict_GetItemString(d, "eval_code");
if (eval_code == NULL) {
return 1;
}
Py_DECREF(m);
Py_DECREF(d);
return 0;
}
......@@ -5,6 +5,9 @@
*/
int
runpython_init();
runpython_init_js();
int
runpython_init_py();
#endif /* RUNPYTHON_H */
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