Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > exec code with timeout?

Reply
Thread Tools

exec code with timeout?

 
 
OKB (not okblacke)
Guest
Posts: n/a
 
      09-08-2003
I am fiddling around with a Python-based MUD which allows users to
code MUD objects in Python. This code is executed from within the
server code with "exec". However, sometimes errors in user code can
result in infinite loops, which cause the MUD to hang. I am wondering
if there is a way to put a timeout on the exec, so that it returns
control to the main program if the user code doesn't return within a
certain amount of time.

I am not concerned with security per se here -- in general I can
assume that any users who are using the MUD are trusted and will not
write malicious code. I am chiefly aiming to catch simple,
unintentional programming errors. For instance, I don't want the MUD
to hang just because someone innocently forgot to include a break
inside a "while 1:" block. All I need is a very crude form of control
-- a simple timeout would do.

I have looked at the thread modules, hoping that I could exec the
user code in a separate thread, sleep in the main thread, and then at
the end of the time limit terminate the user code thread. However,
there doesn't seem to be any way to terminate a subthread from within
the main thread. Am I entirely out of luck here, or is there some
module than can do what I want? (I am working primarily on Windows at
this point, but I would like a solution that works on as many
platforms as as possible.)

--
--OKB (not okblacke)
"Do not follow where the path may lead. Go, instead, where there is
no path, and leave a trail."
--author unknown
 
Reply With Quote
 
 
 
 
Graham Fawcett
Guest
Posts: n/a
 
      09-08-2003
OKB (not okblacke) wrote:

> I am fiddling around with a Python-based MUD which allows users to
>code MUD objects in Python. This code is executed from within the
>server code with "exec".
>

Danger, Will Robinson! Unchecked exec() calls are the path to ruin!

>However, sometimes errors in user code can
>result in infinite loops, which cause the MUD to hang. I am wondering
>if there is a way to put a timeout on the exec, so that it returns
>control to the main program if the user code doesn't return within a
>certain amount of time.
>
> I am not concerned with security per se here -- in general I can
>assume that any users who are using the MUD are trusted and will not
>write malicious code.
>


Hanlon's Razor: "Never attribute to malice that which can be adequately
explained by stupidity."

>I am chiefly aiming to catch simple,
>unintentional programming errors. For instance, I don't want the MUD
>to hang just because someone innocently forgot to include a break
>inside a "while 1:" block. All I need is a very crude form of control
>-- a simple timeout would do.
>
>


The Python 2.3 C API now provides a function, PyThreadState_SetAsyncExc,
that
will let you raise an exception in another thread asynchronously, thereby
taking it down. But I don't think there's a Python wrapper function for
it. I
suppose you could write your own...

The RestrictedPython module in Zope may suit your needs; it was designed
for a
similar use scenario. Search the list, there was a discussion about
RestrictedPython not long ago.


-- Graham



 
Reply With Quote
 
 
 
 
OKB (not okblacke)
Guest
Posts: n/a
 
      09-08-2003
Graham Fawcett wrote:

> The RestrictedPython module in Zope may suit your needs; it was
> designed for a
> similar use scenario. Search the list, there was a discussion about
> RestrictedPython not long ago.


Thanks. I looked at the page that was referenced from here, but it
says RestrictedPython "doesn't implement resource limitations, like
preventing scripts from eating up all available RAM or simply never
terminating". Preventing scripts from never terminating is exactly what
I am interested in. (This isn't a halting problem kind of thing -- I
just want to unceremoniously kill exec-ed code that doesn't terminate in
a given amount of time.) Also, it seems a bit heavyweight. The page
implies that it uses a modified compiler, etc.; I don't know how that
would work with running interactively edited code.

--
--OKB (not okblacke)
"Do not follow where the path may lead. Go, instead, where there is
no path, and leave a trail."
--author unknown
 
Reply With Quote
 
Graham Fawcett
Guest
Posts: n/a
 
      09-08-2003
OKB (not okblacke) wrote:

>Graham Fawcett wrote:
>
>
>
>>The RestrictedPython module in Zope may suit your needs; it was
>>designed for a
>>similar use scenario. Search the list, there was a discussion about
>>RestrictedPython not long ago.
>>
>>

>
> Thanks. I looked at the page that was referenced from here, but it
>says RestrictedPython "doesn't implement resource limitations, like
>preventing scripts from eating up all available RAM or simply never
>terminating". Preventing scripts from never terminating is exactly what
>I am interested in. (This isn't a halting problem kind of thing -- I
>just want to unceremoniously kill exec-ed code that doesn't terminate in
>a given amount of time.) Also, it seems a bit heavyweight. The page
>implies that it uses a modified compiler, etc.; I don't know how that
>would work with running interactively edited code.
>
>
>


Hmm... well, again I'd suggest the PyThreadState_SetAsyncExc function. It
shouldn't be that hard to wrap... I'd try it myself, but haven't made it
to 2.3 yet.

Or, if you're in Unix-land, how about forking? Let the user code
run in the child fork, and let the other half take care of the timeout?
It's easy to kill processes.

-- G




 
Reply With Quote
 
Alex Martelli
Guest
Posts: n/a
 
      09-08-2003
Graham Fawcett wrote:
...
>>preventing scripts from eating up all available RAM or simply never
>>terminating". Preventing scripts from never terminating is exactly what
>>I am interested in. (This isn't a halting problem kind of thing -- I
>>just want to unceremoniously kill exec-ed code that doesn't terminate in

...
> Hmm... well, again I'd suggest the PyThreadState_SetAsyncExc function. It
> shouldn't be that hard to wrap... I'd try it myself, but haven't made it
> to 2.3 yet.


Nope -- the attacking script can easily use try/except to defeat attempts
to kill it via PyThreadState_SetAsyncExc . The latter isn't meant for any
"adversarial" situation, but just for potentially _buggy_ threads.


> Or, if you're in Unix-land, how about forking? Let the user code
> run in the child fork, and let the other half take care of the timeout?
> It's easy to kill processes.


That's definitely the best way to go, particularly if you can couple
it with some mechanism such as the BSDs' "jail" concept -- let the
operating system deal with malicious processes (your task in terms of
architecture design then boils down to the inevitable one of defining
the "least-privileges" each given process absolutely HAS to have).


Alex

 
Reply With Quote
 
Alex Martelli
Guest
Posts: n/a
 
      09-08-2003
John J. Lee wrote:

> Alex Martelli <(E-Mail Removed)> writes:
>> Graham Fawcett wrote:

> [...]
>> > Hmm... well, again I'd suggest the PyThreadState_SetAsyncExc function.
>> > It shouldn't be that hard to wrap... I'd try it myself, but haven't
>> > made it
>> > to 2.3 yet.

>>
>> Nope -- the attacking script can easily use try/except to defeat attempts
>> to kill it via PyThreadState_SetAsyncExc . The latter isn't meant for
>> any "adversarial" situation, but just for potentially _buggy_ threads.

> [...]
>
> Which is what the OP asked for, actually -- the users are trusted.


I think you're right -- I had not understood the OP's specs correctly.
In this case, the OP's application seems to be exactly THE typical
use case for the new functionality (which has been kept in C only to
avoid attracting _inappropriate_ use...). See my lightning talk at
OSCON, slides at http://www.strakt.com/docs/os03_threads_interrupt.pdf ,
for a brief explanations of the how's & why and C source code to
wrap the new call if you KNOW it's exactly what you need.


Alex

 
Reply With Quote
 
Paul Moore
Guest
Posts: n/a
 
      09-08-2003
Alex Martelli <(E-Mail Removed)> writes:

> John J. Lee wrote:
>
>> Alex Martelli <(E-Mail Removed)> writes:
>>
>>> Nope -- the attacking script can easily use try/except to defeat attempts
>>> to kill it via PyThreadState_SetAsyncExc . The latter isn't meant for
>>> any "adversarial" situation, but just for potentially _buggy_ threads.

>> [...]
>>
>> Which is what the OP asked for, actually -- the users are trusted.

>
> I think you're right -- I had not understood the OP's specs correctly.
> In this case, the OP's application seems to be exactly THE typical
> use case for the new functionality (which has been kept in C only to
> avoid attracting _inappropriate_ use...). See my lightning talk at
> OSCON, slides at http://www.strakt.com/docs/os03_threads_interrupt.pdf ,
> for a brief explanations of the how's & why and C source code to
> wrap the new call if you KNOW it's exactly what you need.


If
1. You run the code you want to interrupt in the main thread
2. You don't mind the interrupt being a KeyboardInterrupt exception

then you can write the code in pure Python, as follows:

>>> import thread
>>> import time


>>> def alarm(sec):

.... def wait(sec):
.... time.sleep(sec)
.... thread.interrupt_main()
.... thread.start_new_thread(wait, (sec,))

Example:

>>> alarm(5)
>>> while 1:

.... pass
....

-- 5 seconds later...

Traceback (most recent call last):
File "<stdin>", line 2, in ?
KeyboardInterrupt

Hope this helps,
Paul.
--
This signature intentionally left blank
 
Reply With Quote
 
OKB (not okblacke)
Guest
Posts: n/a
 
      09-08-2003
Paul Moore wrote:

>>>> import thread
>>>> import time

>
>>>> def alarm(sec):

> ... def wait(sec):
> ... time.sleep(sec)
> ... thread.interrupt_main()
> ... thread.start_new_thread(wait, (sec,))


This looks perfect! Many thanks.

--
--OKB (not okblacke)
"Do not follow where the path may lead. Go, instead, where there is
no path, and leave a trail."
--author unknown
 
Reply With Quote
 
Paul Moore
Guest
Posts: n/a
 
      09-08-2003
Paul Moore <(E-Mail Removed)> writes:

> If
> 1. You run the code you want to interrupt in the main thread
> 2. You don't mind the interrupt being a KeyboardInterrupt exception
>
> then you can write the code in pure Python, as follows:


A module to wrap PyThreadState_SetAsyncExc isn't exactly hard, either.
Here's one in its entirety (async.c). I'm not sure I believe the
argument in the reference manual that this function is not exposed to
Python to avoid accidental mistakes - why not expose it, but with a
suitably "internal" name, and documentation warnings (much like
sys._getframe). It could easily be thread._async_exc(), for example.

Anyway, here's the code if it's of any interest...

Paul

#include <Python.h>

static PyObject *
async_exc(PyObject *self, PyObject *args)
{
PyObject *exc;
int id;
int n;

if (!PyArg_ParseTuple(args, "iO:async_exc", &id, &exc))
return NULL;

n = PyThreadState_SetAsyncExc(id, exc);
if (n > 1) {
/* Problem - clear the exception... */
PyThreadState_SetAsyncExc(id, NULL);
return NULL;
}

Py_INCREF(Py_None);
return Py_None;
}

static PyMethodDef ModuleMethods[] = {
{"async_exc", async_exc, METH_VARARGS,
"Raise an exception in the given thread."},
{NULL, NULL, 0, NULL} /* Sentinel */
};

PyMODINIT_FUNC
initasync(void)
{
Py_InitModule("async", ModuleMethods);
}

--
This signature intentionally left blank
 
Reply With Quote
 
JCM
Guest
Posts: n/a
 
      09-08-2003
"OKB (not okblacke)" <(E-Mail Removed)> wrote:
> I am fiddling around with a Python-based MUD which allows users to
> code MUD objects in Python. This code is executed from within the
> server code with "exec". However, sometimes errors in user code can
> result in infinite loops, which cause the MUD to hang. I am wondering
> if there is a way to put a timeout on the exec, so that it returns
> control to the main program if the user code doesn't return within a
> certain amount of time.


We've done exactly this for our own MUD project

The way we got around the infinite loop problem was to have the main
Python thread be the one that runs all unknown MUD-code. You can use
signals (on unix) to raise an exception in the main thread. I don't
remember offhand what function we used--maybe os.kill?
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Net::SSH.exec Using the "exec" method interactively Guillermo Riojas Ruby 0 11-26-2010 05:17 PM
Runtime.exec(String[]) Doesn't Always Work, bBut Runtime.exec(String) Does Hal Vaughan Java 11 05-22-2006 04:49 PM
exec "statement" VS. exec "statement in globals(), locals() Ted Python 1 07-22-2004 08:51 AM
exec "statement" VS. exec "statement" in globals(), locals() tedsuzman Python 2 07-21-2004 08:41 PM
Backup Exec 9.1: The Backup Exec job engine system service is not responding Christian Falch Computer Support 1 06-23-2004 02:22 AM



Advertisments