mirror of
https://github.com/QingdaoU/Judger.git
synced 2024-12-29 16:31:42 +00:00
Merge branch 'dev'
This commit is contained in:
commit
f2e1b01392
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,3 +7,5 @@ CMakeLists.txt
|
||||
main
|
||||
demo
|
||||
.DS_Store
|
||||
judger.log
|
||||
*.swp
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
62
judger.c
62
judger.c
@ -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);
|
||||
|
2
logger.h
2
logger.h
@ -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
|
||||
|
4
runner.c
4
runner.c
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user