Merge branch 'dev'

This commit is contained in:
LiYang 2016-04-26 13:05:33 +08:00
commit f2e1b01392
8 changed files with 42 additions and 39 deletions

2
.gitignore vendored
View File

@ -7,3 +7,5 @@ CMakeLists.txt
main
demo
.DS_Store
judger.log
*.swp

View File

@ -7,4 +7,4 @@ before_install:
- sudo apt-get install libseccomp-dev
install:
- sudo python setup.py install
script: sudo python tests/test.py
script: cd tests && sudo python test.py

View File

@ -23,11 +23,12 @@ cd demo && sudo python demo.py
ptrace在很多OJ上都有应用但是不可否认的是ptrace存在一个重大缺点严重影响进程运行的性能因为每次系统调用就要进行两次上下文切换从子进程到父进程然后父进程到子进程。OJ上题目很多都需要大量的输入和输出会产生大量的系统调用导致代码运行时间加长。
##注意
- `runner.c`里面硬编码了系统调用白名单在Ubuntu 14.04 64位系统上测试通过。如果在您的系统上正常程序出现了`Runtime Error`可能是部分系统调用不一致导致的。可以提出issue一起解决请务必提供系统版本和`strace ./FILE_NAME`的结果。目前已知32位系统肯定会出现非白名单系统调用但是因为32位系统无法使用docker一般出现在本地测试环境中。
- 本Judger定位于C/C++语言如果使用Java由于JVM的特殊性请设置`use_sandbox=False max_memory=MEMORY_UNLIMITED`安全方面使用Java自带的安全策略内存限制方面使用`Xms`、`Xmx`等参数。参考[这里](https://github.com/QingdaoU/OnlineJudge/blob/master/judge)关于Java的部分注释。
- `runner.c`里面硬编码了系统调用白名单在Ubuntu 14.04 64位系统上测试通过。如果在您的系统上正常程序出现了`Runtime Error`可能是部分系统调用不一致导致的。如果怀疑是这个原因提出issue请务必提供系统版本和`strace ./FILE_NAME`的结果。目前已知32位系统肯定会出现非白名单系统调用但是因为32位系统无法使用docker一般出现在本地测试环境中。
- 如果使用了 `use_nobody = True` 则需要 `root` 权限启动。
- Python api 请只使用str。
##感谢
- https://github.com/lodevil/Lo-runner
- https://github.com/quark-zju/lrun
- https://github.com/daveho/EasySandbox
- https://github.com/daveho/EasySandbox

View File

@ -13,7 +13,8 @@ def _compile():
max_memory=judger.MEMORY_UNLIMITED,
args=[os.path.join(base_path, "demo.c"), "-o", os.path.join(base_path, "demo")],
env=["PATH=" + os.environ["PATH"]],
use_sandbox=False,
use_sandbox=False,
log_path="test.log",
use_nobody=False)

View File

@ -3,44 +3,40 @@
#include <python2.7/Python.h>
#include "runner.h"
#define RaiseValueError(msg) {PyErr_SetString(PyExc_ValueError, msg); return NULL;}
static PyObject *judger_run(PyObject *self, PyObject *args, PyObject *kwargs) {
struct config config;
struct result result = {0, 0, 0, 0, 0, 0};
PyObject *args_list = NULL, *env_list = NULL, *use_sandbox = NULL, *use_nobody = NULL,
*next = NULL, *args_iter = NULL, *env_iter = NULL;
*next = NULL, *args_iter = NULL, *env_iter = NULL, *log_path = NULL;
int count = 0;
static char *kwargs_list[] = {"path", "in_file", "out_file", "max_cpu_time",
"max_memory", "args", "env", "use_sandbox", "use_nobody", NULL};
"max_memory", "args", "env", "use_sandbox", "use_nobody", "log_path", NULL};
config.path = config.in_file = config.out_file = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sssil|OOOO", kwargs_list, &(config.path), &(config.in_file),
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sssil|OOOOO", kwargs_list, &(config.path), &(config.in_file),
&(config.out_file), &(config.max_cpu_time), &(config.max_memory),
&args_list, &env_list, &use_sandbox, &use_nobody)) {
PyErr_SetString(PyExc_ValueError, "Invalid args and kwargs");
return NULL;
&args_list, &env_list, &use_sandbox, &use_nobody, &log_path)) {
RaiseValueError("Invalid args and kwargs");
}
if (config.max_cpu_time < 1 && config.max_cpu_time != CPU_TIME_UNLIMITED) {
PyErr_SetString(PyExc_ValueError, "max_cpu_time must > 1 ms or unlimited");
return NULL;
RaiseValueError("max_cpu_time must > 1 ms or unlimited");
}
if (config.max_memory < 16 * 1024 * 1024 && config.max_memory != MEMORY_UNLIMITED) {
PyErr_SetString(PyExc_ValueError, "max_memory must > 16M or unlimited");
return NULL;
RaiseValueError("max_memory must > 16M or unlimited");
}
if (access(config.path, F_OK) == -1) {
PyErr_SetString(PyExc_ValueError, "Exec file does not exist");
return NULL;
RaiseValueError("Exec file does not exist");
}
if (access(config.in_file, F_OK) == -1) {
PyErr_SetString(PyExc_ValueError, "in_file does not exist");
return NULL;
RaiseValueError("in_file does not exist");
}
config.args[count++] = config.path;
if (args_list != NULL) {
if (!PyList_Check(args_list)) {
PyErr_SetString(PyExc_ValueError, "args must be a list");
return NULL;
RaiseValueError("args must be a list");
}
args_iter = PyObject_GetIter(args_list);
@ -50,14 +46,12 @@ static PyObject *judger_run(PyObject *self, PyObject *args, PyObject *kwargs) {
break;
}
if (!PyString_Check(next) && !PyUnicode_Check(next)) {
PyErr_SetString(PyExc_ValueError, "arg in args must be a string");
return NULL;
RaiseValueError("arg in args must be a string");
}
config.args[count] = PyString_AsString(next);
count++;
if(count > 95) {
PyErr_SetString(PyExc_ValueError, "Number of args must < 95");
return NULL;
RaiseValueError("Number of args must < 95");
}
}
}
@ -66,8 +60,7 @@ static PyObject *judger_run(PyObject *self, PyObject *args, PyObject *kwargs) {
count = 0;
if (env_list != NULL) {
if (!PyList_Check(env_list)) {
PyErr_SetString(PyExc_ValueError, "env must be a list");
return NULL;
RaiseValueError("env must be a list");
}
env_iter = PyObject_GetIter(env_list);
while (1) {
@ -76,14 +69,12 @@ static PyObject *judger_run(PyObject *self, PyObject *args, PyObject *kwargs) {
break;
}
if (!PyString_Check(next) && !PyUnicode_Check(next)) {
PyErr_SetString(PyExc_ValueError, "env item must be a string");
return NULL;
RaiseValueError("env item must be a string");
}
config.env[count] = PyString_AsString(next);
count++;
if(count > 95) {
PyErr_SetString(PyExc_ValueError, "Number of env must < 95");
return NULL;
RaiseValueError("Number of env must < 95");
}
}
}
@ -91,8 +82,7 @@ static PyObject *judger_run(PyObject *self, PyObject *args, PyObject *kwargs) {
if (use_sandbox != NULL) {
if (!PyBool_Check(use_sandbox)) {
PyErr_SetString(PyExc_ValueError, "use_sandbox must ba a bool");
return NULL;
RaiseValueError("use_sandbox must ba a bool");
}
config.use_sandbox = PyObject_IsTrue(use_sandbox);
}
@ -102,8 +92,7 @@ static PyObject *judger_run(PyObject *self, PyObject *args, PyObject *kwargs) {
if (use_nobody != NULL) {
if (!PyBool_Check(use_nobody)) {
PyErr_SetString(PyExc_ValueError, "use_nobody must be a bool");
return NULL;
RaiseValueError("use_nobody must be a bool");
}
config.use_nobody = PyObject_IsTrue(use_nobody);
}
@ -111,9 +100,18 @@ static PyObject *judger_run(PyObject *self, PyObject *args, PyObject *kwargs) {
config.use_nobody = 1;
}
if (log_path != NULL) {
if (!PyString_Check(log_path)) {
RaiseValueError("log path must be a string");
}
config.log_path = PyString_AsString(log_path);
}
else {
config.log_path = "judger.log";
}
if(config.use_nobody && getuid() != 0) {
PyErr_SetString(PyExc_ValueError, "Root user is required when use_nobody=True");
return NULL;
RaiseValueError("Root user is required when use_nobody=True");
}
run(&config, &result);

View File

@ -149,4 +149,4 @@ void log_add_info(const char *info)
snprintf(log_extra_info + len, log_buffer_size - len, "\n [%s]", info);
}
#endif
#endif

View File

@ -46,8 +46,8 @@ void run(struct config *config, struct result *result) {
int syscalls_whitelist_length = sizeof(syscalls_whitelist) / sizeof(int);
scmp_filter_ctx ctx = NULL;
log_open("judger.log");
log_open(config->log_path);
#ifdef __APPLE__
#warning "setrlimit with RLIMIT_AS to limit memory usage will not work on OSX"

View File

@ -49,6 +49,7 @@ struct config {
char *env[100];
int use_sandbox;
int use_nobody;
char *log_path;
};