zopefoundation / RestrictedPython

A restricted execution environment for Python to run untrusted code.
http://restrictedpython.readthedocs.io/
Other
480 stars 38 forks source link

`print` / `printed` approach is too opinionated to be useful #290

Open dnesting opened 1 month ago

dnesting commented 1 month ago

BUG/PROBLEM REPORT / FEATURE REQUEST

RestrictingNodeTransformer rewrites usage of print, and expects its output to be retrieved with printed. This is too opinionated for my use case (plus I have existing code that I want to use this on that uses a printed variable for its own purpose). I'd like to simply replace the print builtin with my own implementation that I can do whatever I want with, such as collect output in a file or a StringIO or similar where I can do something with it when execution completes.

Unfortunately it doesn't look like I can do that very easily, since the current print handling seems to be pervasive in the transformer's implementation. Overriding the methods in question seems to mean copy-pasting a lot of code.

I can't find any documentation that explains whether or not there's a good reason __builtins__.print just can't be overridden without all of the mangling that occurs in RestrictingNodeTransformer. Is there? Can you recommend a path forward for me?

What I expect to happen:

I'd love to be able to write a replacement print implementation that works something like:

stdout = StringIO()
stderr = StringIO()
glb = {
  'sys': {  # over-simplifying but you get the idea
    'stdout': stdout,
    'stderr': stderr,
  },
  '__builtins__': {}
}

def my_print(*args, sep=' ', end='\n', file=None, flush=False):
  if file is None:
    file = glb['sys']['stdout']
  print(*args, sep=sep, end=end, file=file, flush=flush)

glb['__builtins__']['print'] = my_print

exec(code, glb, {}, mode='exec')

print(stdout.getvalue())  # "...profit!"

What actually happened:

I am forced instead down a _print and PrintCollector journey that requires I modify the code I'm trying to execute by having it do something in the scope of the user code with printed. This seems like it requires a lot of code modification.

What version of Python and Zope/Addons I am using:

RestrictedPython==7.4 Cpython 3.12 on Darwin

d-maurer commented 1 month ago

David Nesting wrote at 2024-10-19 15:30 -0700:

... Unfortunately it doesn't look like I can do that very easily, since the current print handling seems to be pervasive in the transformer's implementation. Overriding the methods in question seems to mean copy-pasting a lot of code.

I think you are wrong (or at least overly pessimistic): I think all you need is override RestrictedNodeTransformer.visit_Name and remove the

            if node.id == 'printed':
            ...
            elif node.id == 'print':
            ...