diff --git a/common/lib/codejail/codejail/safe_exec.py b/common/lib/codejail/codejail/safe_exec.py index 7a39a57690..824a6c2d57 100644 --- a/common/lib/codejail/codejail/safe_exec.py +++ b/common/lib/codejail/codejail/safe_exec.py @@ -23,12 +23,12 @@ def safe_exec(code, globals_dict, locals_dict, future_division=False, assumed_im `future_division` determines whether Python-3-style division is used. - `assumed_imports` is a list of module to make available as implicit + `assumed_imports` is a list of modules to make available as implicit imports for the code. Entries are either a name, "mod", which makes - "import mod" part of the code, or a pair, ("fooey", "f"), which makes + "import mod" part of the code, or a pair, ("f", "fooey"), which makes "import fooey as f" part of the code. The module name can be dotted. - Returns None, changes made by `code` are visible in `locals_dict`. + Returns None. Changes made by `code` are visible in `locals_dict`. """ the_code = [] @@ -53,16 +53,15 @@ def safe_exec(code, globals_dict, locals_dict, future_division=False, assumed_im the_code.append(textwrap.dedent("""\ exec code in g_dict, l_dict - print >>sys.stderr, l_dict.keys() ok_types = (type(None), int, long, float, str, unicode, list, tuple, dict) l_dict = {k:v for k,v in l_dict.iteritems() if isinstance(v, ok_types)} json.dump(l_dict, sys.stdout) """)) - if 0: - print "-- {:-<40}".format("jailed ") + if 1: + print "--{:-<40}".format(" jailed ") print "".join(the_code) - print "-- {:-<40}".format("exec ") + print "--{:-<40}".format(" exec ") print code stdin = json.dumps([code, globals_dict, locals_dict]) @@ -70,3 +69,48 @@ def safe_exec(code, globals_dict, locals_dict, future_division=False, assumed_im if res.status != 0: raise Exception("Couldn't excecute jailed code: %s" % res.stderr) locals_dict.update(json.loads(res.stdout)) + + +def not_safe_exec(code, globals_dict, locals_dict, future_division=False, assumed_imports=None): + """Another implementation of `safe_exec`, but not safe. + + This can be swapped in for debugging problems in sandboxed Python code. + + """ + def straw(d): + """Return only the JSON-safe part of d. + + Used to emulate reading data through a serialization straw. + + """ + jd = {} + for k,v in d.iteritems(): + try: + json.dumps(v) + except TypeError: + continue + else: + jd[k] = v + return json.loads(json.dumps(jd)) + + if future_division: + code = "from __future__ import division\n" + code + + g_dict = straw(globals_dict) + l_dict = straw(locals_dict) + + for modname in assumed_imports or (): + if isinstance(modname, tuple): + name, modname = modname + else: + name = modname + g_dict[name] = lazymod.LazyModule(modname) + + exec code in g_dict, l_dict + + locals_dict.update(straw(l_dict)) + +# Running Python code in the sandbox makes it difficult to debug. +# Turn this on to run the code directly. +if 1: + safe_exec = not_safe_exec