diff options
author | Prabhu Ramachandran | 2011-11-15 01:22:22 +0530 |
---|---|---|
committer | Prabhu Ramachandran | 2011-11-15 01:22:22 +0530 |
commit | 019ad81a980aabb30d5f5ff205f696bab6d1a79a (patch) | |
tree | 388a45850dea79630e807ad8f20d00a31278c296 /python_server.py | |
parent | 544ccd076a4115e4870429e921ccec4a40c599bc (diff) | |
download | online_test-019ad81a980aabb30d5f5ff205f696bab6d1a79a.tar.gz online_test-019ad81a980aabb30d5f5ff205f696bab6d1a79a.tar.bz2 online_test-019ad81a980aabb30d5f5ff205f696bab6d1a79a.zip |
BUG: Adding timeout to test code evaluation.
If a user submitted code with an errant loop that loops forever or locks
up for any reason, it would take the code server down. I now add a
timeout of 3 seconds for the evaluation and tests failing which it is an
error.
Diffstat (limited to 'python_server.py')
-rwxr-xr-x | python_server.py | 25 |
1 files changed, 24 insertions, 1 deletions
diff --git a/python_server.py b/python_server.py index 1670f90..6ade0ff 100755 --- a/python_server.py +++ b/python_server.py @@ -9,19 +9,31 @@ from SimpleXMLRPCServer import SimpleXMLRPCServer import pwd import os from os.path import isdir +import signal +# Timeout for the code to run in seconds. +TIMEOUT = 3 # Set the effective uid nobody = pwd.getpwnam('nobody') os.setegid(nobody.pw_gid) os.seteuid(nobody.pw_uid) +# Raised when the code times-out. +# c.f. http://pguides.net/python/timeout-a-function +class TimeoutException(Exception): + pass + +def timeout_handler(signum, frame): + raise TimeoutException('Code took too long to run.') + def run_code(answer, test_code, in_dir=None): """Tests given Python function (`answer`) with the `test_code` supplied. If the optional `in_dir` keyword argument is supplied it changes the directory to that directory (it does not change it back to the original when - done). + done). This function also timesout when the function takes more than + TIMEOUT seconds to run to prevent runaway code. Returns ------- @@ -32,6 +44,10 @@ def run_code(answer, test_code, in_dir=None): if in_dir is not None and isdir(in_dir): os.chdir(in_dir) + # Add a new signal handler for the execution of this code. + old_handler = signal.signal(signal.SIGALRM, timeout_handler) + signal.alarm(TIMEOUT) + success = False tb = None try: @@ -40,6 +56,8 @@ def run_code(answer, test_code, in_dir=None): exec submitted in g _tests = compile(test_code, '<string>', mode='exec') exec _tests in g + except TimeoutException: + err = 'Code took more than %s seconds to run.'%TIMEOUT except AssertionError: type, value, tb = sys.exc_info() info = traceback.extract_tb(tb) @@ -54,6 +72,11 @@ def run_code(answer, test_code, in_dir=None): err = 'Correct answer' finally: del tb + # Set back any original signal handler. + signal.signal(signal.SIGALRM, old_handler) + + # Cancel the signal if any, see signal.alarm documentation. + signal.alarm(0) return success, err |