Changeset 993


Ignore:
Timestamp:
01/22/09 01:32:19 (3 years ago)
Author:
strat.cristian@…
Message:

Experimental Python Support

This is highly experimental, potentially unsafe. I only enabled it for admins until it's stable.

  • Bash script to compile and link static binaries from Python scripts.
  • Additional unit tests for jrun. (Added several Python test cases.)
  • UI changes for admins only.
Location:
trunk
Files:
10 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/common/job.php

    r991 r993  
    1010//      round_id: Round to submit for. Optional, if missing the job is sent 
    1111//              to all parent rounds. 
    12 //      compiler_id: c, cpp or fpc. 
     12//      compiler_id: c, cpp, fpc, or py. 
    1313//      solution: A string with the file to submit. 
    1414// 
     
    3838 
    3939    // Validate compiler id 
    40     $valid_compilers = array('c', 'cpp', 'fpc'); 
     40    $valid_compilers = array('c', 'cpp', 'fpc', 'py'); 
    4141    if (!array_key_exists('compiler_id', $args)) { 
    4242        $errors['compiler_id'] = "Lipseste compilatorul."; 
    4343    } else if (array_search($args['compiler_id'], $valid_compilers) === false) { 
    4444        $errors['compiler_id'] = "Compilator invalid."; 
     45    } 
     46    // HACK: For the moment, only admin`s are allowed to submit Python jobs. 
     47    // TODO: Remove this once Python support is stable. 
     48    if ('py' == $args['compiler_id'] && !user_is_admin($user)) { 
     49        $errors['compiler_id'] = 'Deocamdata, numai administratorii pot ' 
     50                .'trimite surse Python.'; 
    4551    } 
    4652 
     
    5662 
    5763    // Check task submit security 
    58     if (!security_query($user, 'task-submit', $task)) { 
     64    if ($task && !security_query($user, 'task-submit', $task)) { 
    5965        $errors[] = "Nu ai voie sa trimiti la acest task."; 
    6066    } 
    61     if ($round != null && !security_query($round, 'task-submit', $round)) { 
     67    if ($round && !security_query($round, 'task-submit', $round)) { 
    6268        $errors[] = "Nu poti sa trimiti la aceasta runda."; 
    6369    } 
  • trunk/common/user.php

    r852 r993  
    107107} 
    108108 
     109function user_is_admin($user) { 
     110    if (!$user) { 
     111        return false; 
     112    } 
     113    log_assert_valid(user_validate($user)); 
     114    return $user['security_level'] === 'admin'; 
     115} 
     116 
    109117?> 
  • trunk/eval/classic_grader.php

    r852 r993  
    5656    } 
    5757 
     58    // HACK: Capture run-time stderr for Python jobs. 
     59    // 
     60    // WARNING! This is a security hole! Users may dump input tests 
     61    // on stderr and see them in the monitor page. Currently, only 
     62    // admins are allowed to submit Python. 
     63    // 
     64    // TODO: Come up with a safe way of reporting run-time errors 
     65    // for Python scripts. 
     66    $capture_std = ('py' == $job['compiler_id']); 
     67 
    5868    // Running tests. 
    5969    $test_score = array(); 
     
    101111 
    102112            // Run user program. 
    103             $jrunres = jail_run($userfile, $jaildir, $tparams['timelimit'] * 1000, $tparams['memlimit']); 
     113            $jrunres = jail_run($userfile, $jaildir, $tparams['timelimit'] * 1000, 
     114                        $tparams['memlimit'], $capture_std); 
    104115            log_assert($jrunres['result'] != 'ERROR', "Error in jrun."); 
    105116            if ($jrunres['result'] == 'FAIL') { 
    106117                log_print("Test $testno: User program failed: {$jrunres['message']} ". 
    107118                        "{$jrunres['time']}ms {$jrunres['memory']}kb"); 
     119                if ($capture_std) { 
     120                    // TODO: Come up with a safe way of reporting run-time 
     121                    // errors for Python scripts. 
     122                    $job_message = $jrunres['message'].": " 
     123                            .substr($jrunres['stderr'], 
     124                                    -min(100, strlen($jrunres['stderr']))); 
     125                } else { 
     126                    $job_message = $jrunres['message']; 
     127                } 
    108128                job_test_update($job['id'], $testno, $group_idx, $jrunres['time'], $jrunres['memory'],  
    109                         null, null, 0, $jrunres['message']); 
     129                        null, null, 0, $job_message); 
    110130                // User program failed on this test. Bye bye. 
    111131                continue; 
  • trunk/eval/utilities.php

    r852 r993  
    2525// Returns success value, and a friendly error message in $compiler_message. 
    2626// 
    27 // Can currently handle C, C++ and FreePascal 
     27// Can currently handle C, C++, FreePascal, and Python. 
    2828function compile_file($input_file_name, $output_file_name, &$compiler_message) 
    2929{ 
     
    3535            'pas' => 'fpc -O2 -Xs %file_name%', 
    3636            'fpc' => 'fpc -O2 -Xs %file_name%', 
     37            'py' => IA_JUDGE_PY_COMPILER.' %file_name% %exe_name%', 
    3738    ); 
    38     if (!preg_match("/^(.*)\.(c|cpp|pas|fpc)$/i", $input_file_name, $matches)) { 
     39    if (!preg_match("/^(.*)\.(c|cpp|pas|fpc|py)$/i", $input_file_name, $matches)) { 
    3940        $compiler_message = "Nu am putut sa determin compilatorul ". 
    4041                "pentru '$input_file_name'."; 
     
    5354 
    5455    // Running compiler 
    55     $compiler_message = shell_exec("$cmdline 2>&1 | head -n 25"); 
     56    $compiler_message = shell_exec("$cmdline 2>&1 | head -n 50"); 
    5657 
    5758    // This is the BEST way to fail on compilation errors. 
     
    168169    } 
    169170 
    170     if ($result['result'] == 'OK' && $capture_std) { 
     171    if ($capture_std) { 
    171172        $result['stdout'] = @file_get_contents($jaildir.'jailed_stdout'); 
    172173        if ($result['stdout'] === false) { 
  • trunk/jrun/bad_syscalls

    r651 r993  
    3434mount 
    3535umount 
     36accept 
     37bind 
     38connect 
     39getsockname 
     40getsockopt 
     41listen 
     42recv 
     43recvfrom 
     44send 
     45setsockopt 
     46socket 
     47socketpair 
  • trunk/jrun/run-tests.php

    r852 r993  
    33 
    44require_once(dirname($argv[0]) . "/../config.php"); 
     5require_once(IA_ROOT_DIR . 'eval/config.php'); 
    56require_once(IA_ROOT_DIR . 'common/log.php'); 
    67 
     
    89$jail_dir = "jail"; 
    910$exe_name = "prog"; 
    10 $extra_args = "--block-syscalls-file=bad_syscalls --chroot --verbose"; 
     11$extra_args = "--block-syscalls-file=bad_syscalls --verbose"; 
    1112//$extra_args = "--nice -5 --block-syscalls-file=bad_syscalls --verbose"; 
    12 //$extra_args = "--uid 65534 --gid 65534 --block-syscalls-file=bad_syscalls --verbose"; 
     13//$extra_args = "--uid 65534 --gid 65534 --block-syscalls-file=bad_syscalls --chroot"; 
    1314//$extra_args = "--uid 65534 --gid 65534 --block-syscalls-file=bad_syscalls"; 
     15 
     16// In order to run python tests, download a python distribution, configure, 
     17// make, make install, then specify the top level directory here. 
     18$py_compiler = IA_ROOT_DIR."scripts/pybin.sh ".IA_JUDGE_PY_DISTRO 
     19        ." {$jail_dir}"; 
    1420 
    1521// Parse a source file 
     
    2026    $test_args = $test_exp_res = null; 
    2127    foreach (file("$filename") as $line) { 
    22         if (preg_match("/\/\/ JRUN_ARGS =(.*)$/", $line, $matches)) { 
     28        if (preg_match("/(?:\/\/|#) JRUN_ARGS =(.*)$/", $line, $matches)) { 
    2329            $test_args = trim($matches[1]); 
    2430        } 
    25         if (preg_match("/\/\/ JRUN_RES =(.*)$/", $line, $matches)) { 
     31        if (preg_match("/(?:\/\/|#) JRUN_RES =(.*)$/", $line, $matches)) { 
    2632            $test_exp_res = trim($matches[1]); 
    2733        } 
     
    3440function compile_source($source, $exe) 
    3541{ 
     42    global $py_compiler; 
    3643    if (strpos($source, ".cpp") === strlen($source) - 4) { 
    37         system("g++ -Wall -lm -O2 $source -o $exe", $ret); 
     44        system("g++ -Wall -lm -O2 $source --static -o $exe", $ret); 
    3845    } else if (strpos($source, ".c") === strlen($source) - 2) { 
    39         system("gcc -Wall -lm -O2 $source -o $exe", $ret); 
     46        system("gcc -Wall -lm -O2 $source --static -o $exe", $ret); 
     47    } else if (strpos($source, ".py") === strlen($source) - 3) { 
     48        system("{$py_compiler} $source $exe", $ret); 
    4049    } else { 
    4150        log_error("Can't compile $source, unknown file extension\n"); 
     
    5362    global $jail_dir, $exe_name; 
    5463 
    55     system("rm -rf jail"); 
     64    system("rm -rf $jail_dir"); 
    5665    system("mkdir -p $jail_dir"); 
    5766    system("chmod 777 $jail_dir"); 
    5867    compile_source($filename, "$jail_dir/$exe_name"); 
    59  
    6068    $cmd = "./jrun --dir=$jail_dir --prog=$exe_name $args"; 
    6169 
     
    130138        print("Invalid arguments\n"); 
    131139    } 
    132 } while (true); 
     140} while (false); 
    133141 
    134142?> 
  • trunk/www/macros/macro_tasksubmit.php

    r934 r993  
    6060            <option value="cpp">GNU C++</option> 
    6161            <option value="fpc">FreePascal</option> 
     62            <?php if (user_is_admin($identity_user)) { ?> 
     63                <option value="py">Python (FOARTE EXPERIMENTAL!)</option> 
     64            <?php } ?> 
    6265        </select> 
    6366    </li> 
  • trunk/www/static/js/submit.js

    r852 r993  
    4343    } 
    4444    var ext = f.value.substring(k + 1).toLowerCase(); 
    45     if ('c' == ext || 'cpp' == ext || 'pas' == ext) { 
     45    if ('c' == ext || 'cpp' == ext || 'pas' == ext || 'py' == ext) { 
    4646        if ('pas' == ext) { 
    4747            // choose FreePascal compiler 
  • trunk/www/views/submit.php

    r934 r993  
    5454            <option value="cpp"<?= 'cpp' == fval('compiler_id') ? ' selected="selected"' : '' ?>>GNU C++</option> 
    5555            <option value="fpc"<?= 'fpc' == fval('compiler_id') ? ' selected="selected"' : '' ?>>FreePascal</option> 
     56            <?php if (user_is_admin($identity_user)) { ?> 
     57                <option value="py"<?= 'py' == fval('compiler_id') ? ' selected="selected"' : '' ?>>Python (FOARTE EXPERIMENTAL!)</option> 
     58            <?php } ?> 
    5659        </select> 
    5760        <?= ferr_span('compiler_id') ?> 
Note: See TracChangeset for help on using the changeset viewer.