views:

113

answers:

4

Hello, I'm making a wxpython app that I will compile with the various freezing utility out there to create an executable for multiple platforms.

the program will be a map editer for a tile-based game engine

in this app I want to provide a scripting system so that advanced users can modify the behavior of the program such as modifying project data, exporting the project to a different format ect.

I want the system to work like so.

the user will place the python script they wish to run into a styled textbox and then press a button to execute the script.

I'm good with this so far thats all really simple stuff. obtain the script from the text-box as a string compile it to a cod object with the inbuilt function compile() then execute the script with an exec statment

script = textbox.text #bla bla store the string
code = compile(script, "script", "exec") #make the code object
eval(code, globals())

the thing is, I want to make sure that this feature can't cause any errors or bugs
say if there is an import statement in the script. will this cause any problems taking into account that the code has been compiled with something like py2exe or py2app?
how do I make sure that the user can't break critical part of the program like modifying part of the GUI while still allowing them to modify the project data (the data is held in global properties in it's own module)? I think that this would mean modifying the globals dict that is passed to the eval function.
how to I make sure that this eval can't cause the program to hang due to a long or infinite loop? how do I make sure that an error raised inside the user's code can't crash the whole app?

basically, how to I avoid all those problems that can arise when allowing the user to run their own code?

EDIT: Concerning the answers given

I don't feel like any of the answers so far have really answered my questions yes they have been in part answered but not completely. I'm well aware the it is impossible to completely stop unsafe code. people are just too clever for one man (or even a teem) to think of all the ways to get around a security system and prevent them.

in fact I don't really care if they do. I'm more worried about some one unintentional breaking something they didn't know about. if some one really wanted to they could tear the app to shreds with the scripting functionality, but I couldn't care less. it will be their instance and all the problem they create will be gone when they restart the app unless they have messed with files on the HD. I want to prevent the problems that arise when the user dose something stupid.
things like IOError's, SystaxErrors, InfiniteLoopErrors ect.

now the part about scope has been answered. I now understand how to define what functions and globals can be accessed from the eval function but is there a way to make sure that the execution of their code can be stopped if it is taking too long?
a green thread system perhaps? (green because it would be eval to make users worry about thread safety)

also if a users uses an import module statement to load a module from even the default library that isn't used in the rest of the class. could this cause problems with the app being frozen by Py2exe, Py2app, or Freeze? what if they call a modal out side of the standard library? would it be enough that the modal is present in the same directory as the frozen executable?

I would like to get these answers with out creating a new question but I will if I must.

+4  A: 

Easy answer: don't.

You can forbid certain keywords (import) and operations, and accesses to certain data structures, but ultimately you're giving your power users quite a bit of power. Since this is for a rich client that runs on the user's machine, a malicious user can crash or even trash the whole app if they really feel like it. But it's their instance to crash. Document it well and tell people what not to touch.

That said, I've done this sort of thing for web apps that execute user input and yes, call eval like this:

eval(code, {"__builtins__":None}, {safe_functions})

where safe_functions is a dictionary containing {"name": func} type pairs of functions you want your users to be able to access. If there's some essential data structure that you're positive your users will never want to poke at, just pop it out of globals before passing them in.

Incidentally, Guido addressed this issue on his blog a while ago. I'll see if I can find it.

Edit: found.

Nathon
"Easy answer: don't." -HA! true, however It was my intention in creating this app to 1) learn a lot about python 2) create an application that can really be used efficiently and powerfully. I'm aware that completely preventing the user from breaking something is impossible short of not allow them to run code. but surely it is possible to stop the app from crashing if there code raises an error that they didn't expect under circumstances they didn't anticipate. or stop the execution of their code if it is hanging because something has gone awry.
Ryex
I meant don't restrict it. Adding scripting functionality is great for the power users, but the caveat that they can break stuff pretty much universally applies.
Nathon
You could embed something like PyV8 instead (http://code.google.com/p/pyv8/), so you would still get a full programming language, but you'd have to provide your own globals and add an extra dependency.
l33tnerd
A: 

Short Answer: No

Other related posts:

It is not easy to create a safety net. The details too many and clever hacks are around:

On your design goals:

It seems you are trying to build an extensible system by providing user to modify a lot of behavior and logic.

Easiest option is to ask them to write a script which you can evaluate (eval) during the program run.

How ever, a good design describes , scopes the flexibility and provides scripting mechanism through various design schemes ranging from configuration, plugin to scripting capabilities etc. The scripting apis if well defined can provide more meaningful extensibility. It is safer too.

pyfunc
I can't fully agree nor disagree with the last part. An application that lets me script itself will help me be much more productive (oh, all those X should be Y... well, I'll write a loop that fixes it). It's a cheap solution to help advanced users. But of course "real" configuration and plugins are very convenient, and also accessable for more users.
delnan
@delnan: I completely agree with you. But for most users, it is still more useful provide extensibility via plugins, scripting API etc. The work that an advanced user would do will be very creative but a blank slate usually does not work well with most users.
pyfunc
A: 

I'd suggest providing some kind of plug-in API and allowing users to provide plug-ins in the form of text files. You can then import them as modules into their own namespace, catching syntax errors in the process, and call the various functions defined in the plug-in module, again checking for errors. You can provide an API module that defines the functions/classes from your program that the plug-in module has access to. That gives you the freedom to make changes to your application's architecture without breaking plug-ins, since you can just adapt the API module to expose the functionality in the same way.

kindall
A: 

If you have the option to switch to Tkinter you can use the bundled tcl interpreter to process your script. For that matter you can probably do that with a wxpython app if you don't start the tk event loop; just use the tcl interpreter without creating any windows.

Since the tcl interpreter is a separate thing it should be nearly impossible to crash the python interpreter if you are careful about what commands you expose to tcl. Plus, tcl makes creating DSLs very easy.

Python - the only scripting language with a built-in scripting engine :-).

Bryan Oakley