SeattleTestbed / repy_v2

Seattle Testbed's Repy ("Restricted Python") sandbox, version 2
MIT License
12 stars 50 forks source link

`NameError` inside a virtual namespace causes Internal Error #132

Closed aaaaalbert closed 7 years ago

aaaaalbert commented 7 years ago

In a plain RepyV2 program, all is good:

x

raises the expected Exception (with type 'exceptions.NameError'): name 'x' is not defined, including a proper user-level traceback.

Sure enough we can do this:

try:
  x
except NameError:
  log("No x.")

Inside a virtual namespace, things break:

v = createvirtualnamespace("x", "Minimal Breaking Example")
try:
  v.evaluate(_context)
except:
  log("Never reached.")

log("Nor do we get here. `evaluate` just explodes.")

Full traceback:

Internal Error
---
Uncaught exception!
---
Following is a full traceback, and a user traceback.
The user traceback excludes non-user modules. The most recent call is displayed last.

Full debugging traceback:
  "/private/tmp/repy_v2/RUNNABLE/namespace.py", line 1220, in wrapped_function
  "/private/tmp/repy_v2/RUNNABLE/virtual_namespace.py", line 116, in evaluate
  "/private/tmp/repy_v2/RUNNABLE/safe.py", line 604, in safe_run
  "Minimal Breaking Example", line 1, in <module>

User traceback:
  "/private/tmp/repy_v2/RUNNABLE/namespace.py", line 1220, in wrapped_function
  "/private/tmp/repy_v2/RUNNABLE/virtual_namespace.py", line 116, in evaluate
  "/private/tmp/repy_v2/RUNNABLE/safe.py", line 604, in safe_run
  "Minimal Breaking Example", line 1, in <module>

Exception (with type 'exceptions.NameError'): name 'x' is not defined
---

131 (different Exception types inside and outside the sandbox) could be related.

aaaaalbert commented 7 years ago

This traces back to wrapping createvirtualnamespace and using the wrapped definition in namespace.py (as opposed to repy.py's override. With the wrapped call, the logic at the bottom of namespace.py is triggered when VirtualNamespace.evaluate, the wrapped namespace object method, is called. What happens is that Repy exceptions (like SocketWouldBlockError, subclassing RepyException) that are raised inside the virtual namespace match this clause, whereas pure Python errors like NameError land down here and are considered fatal.

The fix I'll propose shortly will add a check and reraise if the blanket except catches for a wrapped VirtualNamespace call. I also have a unit test to go with this.