Git Product home page Git Product logo

go-judge's Introduction

go-judge

Go Reference Go Report Card Release Build

中文文档

Fast, Simple, Secure

Quick Start

Install & Run

Download compiled executable go-judge for your platform from Release and run.

Or, by docker

docker run -it --rm --privileged --shm-size=256m -p 5050:5050 --name=go-judge criyle/go-judge

REST API

A REST service to run program in restricted environment (Listening on localhost:5050 by default).

  • /run POST execute program in the restricted environment (examples below)
  • /file GET list all cached file id to original name map
  • /file POST prepare a file in the go judge (in memory), returns fileId (can be referenced in /run parameter)
  • /file/:fileId GET downloads file from go judge (in memory), returns file content
  • /file/:fileId DELETE delete file specified by fileId
  • /ws WebSocket for /run
  • /stream WebSocket for stream run
  • /version gets build git version (e.g. v1.4.0) together with runtime information (go version, os, platform)
  • /config gets some configuration (e.g. fileStorePath, runnerConfig) together with some supported features

REST API Interface

interface LocalFile {
    src: string; // absolute path for the file
}

interface MemoryFile {
    content: string | Buffer; // file contents
}

interface PreparedFile {
    fileId: string; // fileId defines file uploaded by /file
}

interface Collector {
    name: string; // file name in copyOut
    max: number;  // maximum bytes to collect from pipe
    pipe?: boolean; // collect over pipe or not (default false)
}

interface Symlink {
    symlink: string; // symlink destination (v1.6.0+)
}

interface StreamIn {
    streamIn: boolean; // stream input (v1.8.1+)
}

interface StreamOut {
    streamOut: boolean; // stream output (v1.8.1+)
}

interface Cmd {
    args: string[]; // command line argument
    env?: string[]; // environment

    // specifies file input / pipe collector for program file descriptors (null is reserved for pipe mapping and must be filled by in / out)
    files?: (LocalFile | MemoryFile | PreparedFile | Collector | StreamIn | StreamOut  null)[];
    tty?: boolean; // enables tty on the input and output pipes (should have just one input & one output)
    // Notice: must have TERM environment variables (e.g. TERM=xterm)

    // limitations
    cpuLimit?: number;     // ns
    realCpuLimit?: number; // deprecated: use clock limit instead (still working)
    clockLimit?: number;   // ns
    memoryLimit?: number;  // byte
    stackLimit?: number;   // byte (N/A on windows, macOS cannot set over 32M)
    procLimit?: number;
    cpuRateLimit?: number; // limit cpu usage (1000 equals 1 cpu)
    cpuSetLimit?: string; // Linux only: set the cpuSet for cgroup
    strictMemoryLimit?: boolean; // deprecated: use dataSegmentLimit instead (still working)
    dataSegmentLimit?: boolean; // Linux only: use (+ rlimit_data limit) enable by default if cgroup not enabled
    addressSpaceLimit?: boolean; // Linux only: use (+ rlimit_address_space limit) 

    // copy the correspond file to the container dst path
    copyIn?: {[dst:string]:LocalFile | MemoryFile | PreparedFile | Symlink};

    // copy out specifies files need to be copied out from the container after execution
    // append '?' after file name will make the file optional and do not cause FileError when missing
    copyOut?: string[];
    // similar to copyOut but stores file in go judge and returns fileId, later download through /file/:fileId
    copyOutCached?: string[];
    // specifies the directory to dump container /w content
    copyOutDir: string
    // specifies the max file size to copy out
    copyOutMax?: number; // byte
}

enum Status {
    Accepted = 'Accepted', // normal
    MemoryLimitExceeded = 'Memory Limit Exceeded', // mle
    TimeLimitExceeded = 'Time Limit Exceeded', // tle
    OutputLimitExceeded = 'Output Limit Exceeded', // ole
    FileError = 'File Error', // fe
    NonzeroExitStatus = 'Nonzero Exit Status',
    Signalled = 'Signalled',
    InternalError = 'Internal Error', // system error
}

interface PipeIndex {
    index: number; // the index of cmd
    fd: number;    // the fd number of cmd
}

interface PipeMap {
    in: PipeIndex;  // input end of the pipe
    out: PipeIndex; // output end of the pipe
    // enable pipe proxy from in to out, 
    // content from in will be discarded if out closes
    proxy?: boolean; 
    name?: string;   // copy out proxy content if proxy enabled
    // limit the copy out content size, 
    // proxy will still functioning after max
    max?: number;    
}

enum FileErrorType {
    CopyInOpenFile = 'CopyInOpenFile',
    CopyInCreateFile = 'CopyInCreateFile',
    CopyInCopyContent = 'CopyInCopyContent',
    CopyOutOpen = 'CopyOutOpen',
    CopyOutNotRegularFile = 'CopyOutNotRegularFile',
    CopyOutSizeExceeded = 'CopyOutSizeExceeded',
    CopyOutCreateFile = 'CopyOutCreateFile',
    CopyOutCopyContent = 'CopyOutCopyContent',
    CollectSizeExceeded = 'CollectSizeExceeded',
}

interface FileError {
    name: string; // error file name
    type: FileErrorType; // type
    message?: string; // detailed message
}

interface Request {
    requestId?: string; // for WebSocket requests
    cmd: Cmd[];
    pipeMapping?: PipeMap[];
}

interface CancelRequest {
    cancelRequestId: string;
};

// WebSocket request
type WSRequest = Request | CancelRequest;

interface Result {
    status: Status;
    error?: string; // potential system error message
    exitStatus: number;
    time: number;   // ns (cgroup recorded time)
    memory: number; // byte
    runTime: number; // ns (wall clock time)
    // copyFile name -> content
    files?: {[name:string]:string};
    // copyFileCached name -> fileId
    fileIds?: {[name:string]:string};
    // fileError contains detailed file errors
    fileError?: FileError[];
}

// WebSocket results
interface WSResult {
    requestId: string;
    results: Result[];
    error?: string;
}

// Stream request & responses
interface Resize {
    index: number;
    fd: number;
    rows: number;
    cols: number;
    x: number;
    y: number;
}

interface Input {
    index: number;
    fd: number;
    content: Buffer;
}

interface Output {
    index: number;
    fd: number;
    content: Buffer;
}

Example Request & Response

FFI
var ffi = require('ffi-napi');

var go_judge = ffi.Library('./go_judge', {
    'Init': ['int', ['string']],
    'Exec': ['string', ['string']],
    'FileList': ['string', []],
    'FileAdd': ['string', ['string']],
    'FileGet': ['string', ['string']],
    'FileDelete': ['string', ['string']]
});

if (go_judge.Init(JSON.stringify({
    cinitPath: "/judge/cinit",
    parallelism: 4,
}))) {
    console.log("Failed to init go judge");
}

const result = JSON.parse(go_judge.Exec(JSON.stringify({
    "cmd": [{
        "args": ["/bin/cat", "test.txt"],
        "env": ["PATH=/usr/bin:/bin"],
        "files": [{
            "content": ""
        }, {
            "name": "stdout",
            "max": 10240
        }, {
            "name": "stderr",
            "max": 10240
        }],
        "cpuLimit": 10000000000,
        "memoryLimit": 104857600,
        "procLimit": 50,
        "copyIn": {
            "test.txt": {
                "content": "TEST"
            }
        }
    }]
})));
console.log(result);

// Async
go_judge.Exec.async(JSON.stringify({
    "cmd": [{
        "args": ["/bin/cat", "test.txt"],
        "env": ["PATH=/usr/bin:/bin"],
        "files": [{
            "content": ""
        }, {
            "name": "stdout",
            "max": 10240
        }, {
            "name": "stderr",
            "max": 10240
        }],
        "cpuLimit": 10000000000,
        "memoryLimit": 104857600,
        "procLimit": 50,
        "copyIn": {
            "test.txt": {
                "content": "TEST"
            }
        }
    }]
}), (err, res) => {
    if (err) throw err;
    console.log(JSON.parse(res));
});

const fileAdd = (param) => new Promise((resolve, reject) => {
    go_judge.FileAdd.async(JSON.stringify(param), (err, res) => {
        if (err != null) { reject(err); } else { resolve(res); }
    });
});
const fileList = () => new Promise((resolve, reject) => {
    go_judge.FileList.async((err, res) => {
        if (err != null && res == null) { reject(err); } else { resolve(JSON.parse(res)); }
    });
});
const fileGet = (param) => new Promise((resolve, reject) => {
    go_judge.FileGet.async(JSON.stringify(param), (err, res) => {
        if (err != null && res == null) { reject(err); } else { resolve(res); }
    });
});
const fileDelete = (param) => new Promise((resolve, reject) => {
    go_judge.FileDelete.async(JSON.stringify(param), (err, res) => {
        if (err != null && res == null) { reject(err); } else { resolve(res); }
    });
});

const fileOps = async () => {
    const fileId = await fileAdd({ name: 'Name', content: 'Content' });
    console.log(fileId);
    const list = await fileList();
    console.log(list);
    const file = await fileGet({ id: fileId });
    console.log(file);
    const d = await fileDelete({ id: fileId });
    console.log(d);
    const e = await fileList();
    console.log(e);
};

fileOps();

Output:

{
  requestId: '',
  results: [
    {
      status: 'Accepted',
      exitStatus: 0,
      time: 814048,
      memory: 253952,
      files: [Object]
    }
  ]
}

Please use PostMan or similar tools to send request to http://localhost:5050/run

Single (this example require `apt install g++` inside the container)
{
    "cmd": [{
        "args": ["/usr/bin/g++", "a.cc", "-o", "a"],
        "env": ["PATH=/usr/bin:/bin"],
        "files": [{
            "content": ""
        }, {
            "name": "stdout",
            "max": 10240
        }, {
            "name": "stderr",
            "max": 10240
        }],
        "cpuLimit": 10000000000,
        "memoryLimit": 104857600,
        "procLimit": 50,
        "copyIn": {
            "a.cc": {
                "content": "#include <iostream>\nusing namespace std;\nint main() {\nint a, b;\ncin >> a >> b;\ncout << a + b << endl;\n}"
            }
        },
        "copyOut": ["stdout", "stderr"],
        "copyOutCached": ["a.cc", "a"]
    }]
}
[
    {
        "status": "Accepted",
        "exitStatus": 0,
        "time": 303225231,
        "memory": 32243712,
        "runTime": 524177700,
        "files": {
            "stderr": "",
            "stdout": ""
        },
        "fileIds": {
            "a": "5LWIZAA45JHX4Y4Z",
            "a.cc": "NOHPGGDTYQUFRSLJ"
        }
    }
]
{
    "cmd": [{
        "args": ["a"],
        "env": ["PATH=/usr/bin:/bin"],
        "files": [{
            "content": "1 1"
        }, {
            "name": "stdout",
            "max": 10240
        }, {
            "name": "stderr",
            "max": 10240
        }],
        "cpuLimit": 10000000000,
        "memoryLimit": 104857600,
        "procLimit": 50,
        "copyIn": {
            "a": {
                "fileId": "5LWIZAA45JHX4Y4Z"
            }
        }
    }]
}
[
    {
        "status": "Accepted",
        "exitStatus": 0,
        "time": 1173000,
        "memory": 10637312,
        "runTime": 1100200,
        "files": {
            "stderr": "",
            "stdout": "2\n"
        }
    }
]
Multiple (interaction problem)
{
    "cmd": [{
        "args": ["/bin/cat", "1"],
        "env": ["PATH=/usr/bin:/bin"],
        "files": [{
            "content": ""
        }, null, {
            "name": "stderr",
            "max": 10240
        }],
        "cpuLimit": 1000000000,
        "memoryLimit": 1048576,
        "procLimit": 50,
        "copyIn": {
            "1": { "content": "TEST 1" }
        },
        "copyOut": ["stderr"]
    },
    {
        "args": ["/bin/cat"],
        "env": ["PATH=/usr/bin:/bin"],
        "files": [null, {
            "name": "stdout",
            "max": 10240
        }, {
            "name": "stderr",
            "max": 10240
        }],
        "cpuLimit": 1000000000,
        "memoryLimit": 1048576,
        "procLimit": 50,
        "copyOut": ["stdout", "stderr"]
    }],
    "pipeMapping": [{
        "in" : {"index": 0, "fd": 1 },
        "out" : {"index": 1, "fd" : 0 }
    }]
}
[
    {
        "status": "Accepted",
        "exitStatus": 0,
        "time": 1545123,
        "memory": 253952,
        "runTime": 4148800,
        "files": {
            "stderr": ""
        },
        "fileIds": {}
    },
    {
        "status": "Accepted",
        "exitStatus": 0,
        "time": 1501463,
        "memory": 253952,
        "runTime": 5897700,
        "files": {
            "stderr": "",
            "stdout": "TEST 1"
        },
        "fileIds": {}
    }
]
Compile On Windows (cygwin)
{
    "cmd": [{
        "args": ["C:\\Cygwin\\bin\\g++", "a.cc", "-o", "a"],
        "env": ["PATH=C:\\Cygwin\\bin;"],
        "files": [{
            "content": ""
        }, {
            "name": "stdout",
            "max": 10240
        }, {
            "name": "stderr",
            "max": 10240
        }],
        "cpuLimit": 10000000000,
        "memoryLimit": 104857600,
        "procLimit": 50,
        "copyIn": {
            "a.cc": {
                "content": "#include <iostream>\n#include <signal.h>\n#include <unistd.h>\nusing namespace std;\nint main() {\nint a, b;\ncin >> a >> b;\ncout << a + b << endl;\n}"
            }
        },
        "copyOutCached": ["a.exe"]
    }]
}
[
    {
        "status": "Accepted",
        "exitStatus": 0,
        "time": 140625000,
        "memory": 36286464,
        "files": {
            "stderr": "",
            "stdout": ""
        },
        "fileIds": {
            "a.exe": "HLQH2OF4MXUUJBCB"
        }
    }
]
Infinite loop with cpu rate control
{
 "cmd": [{
  "args": ["/usr/bin/python3", "1.py"],
  "env": ["PATH=/usr/bin:/bin"],
  "files": [{"content": ""}, {"name": "stdout","max": 10240}, {"name": "stderr","max": 10240}],
  "cpuLimit": 3000000000,
  "clockLimit": 4000000000,
  "memoryLimit": 104857600,
  "procLimit": 50,
  "cpuRate": 0.1,
  "copyIn": {
    "1.py": {
      "content": "while True:\n    pass"
    }
  }}]
}
[
    {
        "status": "Time Limit Exceeded",
        "exitStatus": 9,
        "time": 414803599,
        "memory": 3657728,
        "runTime": 4046054900,
        "files": {
            "stderr": "",
            "stdout": ""
        }
    }
]

Documentation

Prerequisite

  • Linux Kernel Version >= 3.10
  • Cgroup file system mounted at /sys/fs/cgroup. Usually done by systemd

Architecture

+----------------------------------------------------------------------------------+
| Transport Layer (HTTP / WebSocket / FFI / ...)                                   |
+----------------------------------------------------------------------------------+
| Sandbox Worker (Environment Pool w/ Environment Builder )                        |
+-----------------------------------------------------------+----------------------+
| EnvExec                                                   | File Store           |
+--------------------+----------------+---------------------+---------------+------+
| Linux (go-sandbox) | Windows (winc) | macOS (app sandbox) | Shared Memory | Disk |
+--------------------+----------------+---------------------+---------------+------+

Command Line Arguments

Server:

  • The default binding address for the go judge is localhost:5050. Can be specified with -http-addr flag.
  • By default gRPC endpoint is disabled, to enable gRPC endpoint, add -enable-grpc flag.
  • The default binding address for the gRPC go judge is localhost:5051. Can be specified with -grpc-addr flag.
  • The default log level is info, use -silent to disable logs or use -release to enable release logger (auto turn on if in docker).
  • -auth-token to add token-based authentication to REST / gRPC
  • By default, the GO debug endpoints (localhost:5052/debug) are disabled, to enable, specifies -enable-debug, and it also enables debug log
  • By default, the prometheus metrics endpoints (localhost:5052/metrics) are disabled, to enable, specifies -enable-metrics
  • Monitoring HTTP endpoint is enabled if metrics / debug is enabled, the default addr is localhost:5052 and can be specified by -monitor-addr

Sandbox:

  • The default concurrency equal to number of CPU, Can be specified with -parallelism flag.
  • The default file store is in memory, local cache can be specified with -dir flag.
  • The default CGroup prefix is gojudge, Can be specified with -cgroup-prefix flag.
  • -src-prefix to restrict src copyIn path split by comma (need to be absolute path) (example: /bin,/usr)
  • -time-limit-checker-interval specifies time limit checker interval (default 100ms) (valid value: [1ms, 1s])
  • -output-limit specifies size limit of POSIX rlimit of output (default 256MiB)
  • -extra-memory-limit specifies the additional memory limit to check memory limit exceeded (default 16KiB)
  • -copy-out-limit specifies the default file copy out max (default 64MiB)
  • -open-file-limit specifies the max number of open files (default 256)
  • -cpuset specifies cpuset.cpus cgroup for each container (Linux only)
  • -container-cred-start specifies container setuid / setgid credential start point (default: 0 (disabled)) (Linux only)
    • for example, by default container 0 will run with 10001 uid & gid and container 1 will run with 10002 uid & gid...
  • -enable-cpu-rate enabled cpu cgroup to control cpu rate using cfs_quota & cfs_period control (Linux only)
    • -cpu-cfs-period specifies cfs_period if cpu rate is enabled (default 100ms) (valid value: [1ms, 1s])
  • -seccomp-conf specifies seccomp filter setting to load when running program (need build tag seccomp) (Linux only)
    • for example, by strace -c prog to get all syscall needed and restrict to that sub set
    • however, the syscall count in one platform(e.g. x86_64) is not suitable for all platform, so this option is not recommended
    • the program killed by seccomp filter will have status Dangerous Syscall
  • -pre-fork specifies number of container to create when server starts
  • -tmp-fs-param specifies the tmpfs parameter for /w and /tmp when using default mounting (Linux only)
  • -file-timeout specifies maximum TTL for file created in file store (e.g. 30m)
  • -mount-conf specifies detailed mount configuration, please refer mount.yaml as a reference (Linux only)
  • -container-init-path specifies path to cinit (do not use, debug only) (Linux only)

Environment Variables

Environment variable will be override by command line arguments if they both present and all command line arguments have its correspond environment variable (e.g. ES_HTTP_ADDR). Run go-judge --help to see all the environment variable configurations.

Build go judge

Build by your own docker build -t go-judge -f Dockerfile.exec .

For cgroup v1, the go-judge need root privilege to create cgroup. Either creates sub-directory /sys/fs/cgroup/cpuacct/go_judge, /sys/fs/cgroup/memory/go_judge, /sys/fs/cgroup/pids/go_judge and make execution user readable or use sudo to run it.

For cgroup v2, systemd dbus will be used to create a transient scope for cgroup integration.

Build Shared object

Build container init cinit:

go build -o cinit ./cmd/cinit

Build go_judge.so:

go build -buildmode=c-shared -o go_judge.so ./cmd/ffi/

For example, in JavaScript, run with ffi-napi (seems node 14 is not supported yet):

Build gRPC Proxy

Build go build ./cmd/go-judge-proxy

Run ./go-judge-proxy, connect to gRPC endpoint expose as a REST endpoint.

Build go judge Shell

Build go build ./cmd/go-judge-shell

Run ./go-judge-shell, connect to gRPC endpoint with interactive shell.

Return Status

  • Accepted: Program exited with status code 0 within time & memory limits
  • Memory Limit Exceeded: Program uses more memory than memory limits
  • Time Limit Exceeded:
    • Program uses more CPU time than cpuLimit
    • Or, program uses more clock time than clockLimit
  • Output Limit Exceeded:
    • Program output more than pipeCollector limits
    • Or, program output more than output-limit
  • File Error:
    • CopyIn file is not existed
    • Or, CopyIn file too large for container file system
    • Or, CopyOut file is not existed after program exited
  • Non Zero Exit Status: Program exited with non 0 status code within time & memory limits
  • Signalled: Program exited with signal (e.g. SIGSEGV)
  • Dangerous Syscall: Program killed by seccomp filter
  • Internal Error:
    • Program is not exist
    • Or, container create not successful (e.g. not privileged docker)
    • Or, other errors

Container Root Filesystem

For linux platform, the default mounts points are bind mounting host's /lib, /lib64, /usr, /bin, /etc/ld.so.cache, /etc/alternatives, /etc/fpc.cfg, /dev/null, /dev/urandom, /dev/random, /dev/zero, /dev/full and mounts tmpfs at /w, /tmp and creates /proc.

To customize mount points, please look at example mount.yaml file.

tmpfs size for /w and /tmp is configured through -tmp-fs-param with default value size=128m,nr_inodes=4k

If a file named /.env exists in the container rootfs, the container will load the file as environment variable line by line.

If a bind mount is specifying a target within the previous mounted one, please ensure the target exists in the previous mount point.

Packages

  • envexec: run single / group of programs in parallel within restricted environment and resource constraints
  • env: reference implementation environments to inject into envexec

Windows Support

  • Build go-judge by: go build ./cmd/go-judge/
  • Build go_judge.dll: (need to install gcc as well) go build -buildmode=c-shared -o go_judge.so ./cmd/ffi/
  • Run: ./go-judge

Windows Security

MacOS Support

  • Build go-judge by: go build ./cmd/go-judge/
  • Build go_judge.dylib: (need to install XCode) go build -buildmode=c-shared -o go_judge.dylib ./cmd/ffi/
  • Run: ./go-judge

MacOS Security

  • sandbox-init profile deny network access and file read / write and read / write to /Users directory

Notice

cgroup v2 support

The cgroup v2 is supported by go-judge now when running as root since more Linux distribution are enabling cgroup v2 by default (e.g. Ubuntu 21.10+, Fedora 31+). However, for kernel < 5.19, due to missing memory.max_usage_in_bytes in memory controller, the memory usage is now accounted by maxrss returned by wait4 syscall. Thus, the memory usage appears higher than those who uses cgroup v1. For kernel >= 5.19, memory.peak is being used.

When running in containers, the go-judge will migrate all processed into /api hierarchy to enable nesting support.

When running in Linux distributions powered by systemd, the go-judge will contact systemd via dbus to create a transient scope as cgroup root.

CentOS 7

By default, user namespace is disabled and it can be enabled following stack overflow

echo user.max_user_namespaces=10000 >> /etc/sysctl.d/98-userns.conf
sysctl -p
# reboot make the config effective
reboot

Memory Usage

The controller will consume 20M memory and each container will consume 20M + size of tmpfs 2 * 128M. For each request, it consumes as much as user program limit + extra limit (16k) + total copy out max. Notice that the cached file stores in the shared memory (/dev/shm) of the host, so please ensure enough size allocated.

For example, when concurrency = 4, the container itself can consume as much as 60 + (20+32) * 4M = 268M + 4 * total copy out + total max memory of requests.

Due to limitation of GO runtime, the memory will not return to OS automatically, which could lead to OOM killer. The background worker was introduced to checks heap usage and invokes GC when necessary.

  • -force-gc-target default 20m, the minimal size to trigger GC
  • -force-gc-interval default 5s, the interval to check memory usage

WebSocket Stream Interface

Websocket stream interface is used to run command interactively with inputs and outputs pumping from the command. All message is transmitted in binary format for maximum compatibility.

+--------+--------+---...
| type   | payload ...
+--------|--------+---...
request:
type = 
  1 - request (payload = JSON encoded request)
  2 - resize (payload = JSON encoded resize request)
  3 - input (payload = 1 byte (4-bit index + 4-bit fd), followed by content)
  4 - cancel (no payload)

response:
type = 
  1 - response (payload = JSON encoded response)
  2 - output (payload = 1 byte (4-bit index + 4-bit fd), followed by content)

Any incomplete / invalid message will be treated as error.

Benchmark

By wrk with t.lua: wrk -s t.lua -c 1 -t 1 -d 30s --latency http://localhost:5050/run.

However, these results are not the real use cases since the running time depends on the actual program specifies in the request. Normally, the go judge consumes ~1ms more compare to running without sandbox.

wrk.method = "POST"
wrk.body   = '{"cmd":[{"args":["/bin/cat","a.hs"],"env":["PATH=/usr/bin:/bin"],"files":[{"content":""},{"name":"stdout","max":10240},{"name":"stderr","max":10240}],"cpuLimit":10000000000,"memoryLimit":104857600,"procLimit":50,"copyIn":{"a.hs":{"content":"main = putStrLn \\"Hello, World!\\""},"b":{"content":"TEST"}}}]}'
wrk.headers["Content-Type"] = "application/json;charset=UTF-8"
  • Single thread ~800-860 op/s Windows 10 WSL2 @ 5800X
  • Multi thread ~4500-6000 op/s Windows 10 WSL2 @ 5800X

Single thread:

Running 30s test @ http://localhost:5050/run
  1 threads and 1 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.16ms  132.89us   6.20ms   90.15%
    Req/Sec     0.87k    19.33     0.91k    85.33%
  Latency Distribution
     50%    1.13ms
     75%    1.18ms
     90%    1.27ms
     99%    1.61ms
  25956 requests in 30.01s, 6.88MB read
Requests/sec:    864.88
Transfer/sec:    234.68KB

go-judge's People

Contributors

arargon avatar boyanzh avatar criyle avatar dependabot[bot] avatar source-roc avatar undefined-moe avatar wxh06 avatar yzy-1 avatar zx2c4 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

go-judge's Issues

websocket 在 close 的时候会在日志中产生一行 warning

如题。连接 ws://localhost:5050/ws 并发送一条执行请求,可以正常收到结果。但是当请求结束,客户端退出时,无论是显式调用 connection.close() 关闭连接还是直接 exit 退出程序,均会在服务端(executorserver)产生格式如同下面的 warning:

// 直接退出
{"level":"warn","ts":1663066810.5931816,"caller":"ws_executor/websocket.go:146","msg":"ws read error:websocket: close 1006 (abnormal closure): unexpected EOF"}
// 显式调用 close
{"level":"warn","ts":1663066699.9190106,"caller":"ws_executor/websocket.go:146","msg":"ws read error:websocket: close 1000 (normal): Normal connection closure"}

测试代码:

#!/usr/bin/env node
var WebSocketClient = require('websocket').client;

var client = new WebSocketClient();

client.on('connectFailed', function(error) {
  console.log('Connect Error: ' + error.toString());
});

client.on('connect', function(connection) {
  console.log('WebSocket Client Connected');
  connection.on('error', function(error) {
    console.log("Connection Error: " + error.toString());
  });
  connection.on('close', function() {
    console.log('echo-protocol Connection Closed');
  });
  connection.on('message', function(message) {
    if (message.type === 'utf8') {
      console.log("Received: '" + message.utf8Data + "'");
      connection.close();
    }
  });

  function test() {
    if (connection.connected) {
      connection.sendUTF(
String.raw`{
  "requestId":"hello",
    "cmd": [{
        "args": ["/usr/bin/g++", "a.cc", "-o", "a"],
        "env": ["PATH=/usr/bin:/bin"],
        "files": [{
            "content": ""
        }, {
            "name": "stdout",
            "max": 10240
        }, {
            "name": "stderr",
            "max": 10240
        }],
        "cpuLimit": 10000000000,
        "memoryLimit": 104857600,
        "procLimit": 50,
        "copyIn": {
            "a.cc": {
                "content": "#include <iostream>\nusing namespace std;\nint main() {\nint a, b;\ncin >> a >> b;\ncout << a + b << endl;\n}"
            }
        },
        "copyOut": ["stdout", "stderr"],
        "copyOutCached": ["a.cc", "a"],
        "copyOutDir": "1"
    }]
}`
      );
    }
  }
  test();
});

client.connect('ws://localhost:5050/ws');

"message": "open a: no such file or directory"

在运行第一个示例(g++示例)的时候,需要创建或者上传额外的文件吗?

我请求的地址是:http://***********:5050/run

得到了这样的响应信息
[
{
"status": "Internal Error",
"exitStatus": 0,
"error": "execve: start: execve: no such file or directory",
"time": 255185,
"memory": 0,
"runTime": 0,
"files": {
"stderr": "",
"stdout": ""
},
"fileIds": {
"a.cc": "3TIW2DYO"
},
"fileError": [
{
"name": "a",
"type": "CopyOutOpen",
"message": "open a: no such file or directory"
}
]
}
]

Why did the run fail?

I installed Docker on my machine and then called your /run API, but I got this result, why did it fail?

[
-{
"status": "Internal Error",
"exitStatus": 0,
"error": "failed to get environment container: failed to start container operation not permitted",
"time": 0,
"memory": 0
}
]

proposal: use tmpfs as file store on linux

Currently, the default file store is based on a map of byte array in memory.

This purposal is to implement a new file store to using tmpfs location (/dev/shm). After this change, in memory file store will be deprecated so that there will alway be a path for file store.

After this change, a new boolean field absPath will be added to Cmd. When absPath is set to true, copyOutCached fileId will prefixed with the file store location (e.g. /dev/shm/go-judge/fileId).

On other platforms, a temporary forlder will be used as file store.

This proposal is aimed to reduce the memory consumption and provides ability to access file in file srore easier for clients.

关于某段代码Non Zero Exit Status的疑问

你好,当我在编译运行以下这段代码本地都是返回0但是沙箱却不是返回0




//========--------- From Origami404, under GPLv3 ---------========//
//========--------- This file is generated automatically to avoid copying/pasting the code ---------========//
#ifndef HEADER_UTILS_H__
#define HEADER_UTILS_H__

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

/**
 * @brief 检查 OOM 的 malloc 版本, 一旦 OOM 则退出程序
 *
 * @param s 待分配字节数
 * @return void* 指向分配好的内存区域的指针, 保证非空
 */
static inline void* checked_malloc(size_t s) {
    void *p = malloc(s);
    if (!p) {
        fprintf(stderr, "Out of memory.");
        exit(EXIT_FAILURE);
    }
    return p;
}

static inline void impl__assert_with_message(char const expr[static 1], char const message[static 1], const char file[static 1], unsigned long line) {
    fprintf(stderr, "%s:%ld  Assert fail: %s (%s)\n", file, line, message, expr);
    fflush(stderr);
    exit(EXIT_FAILURE);
}

#define assertm(expr, message) \
    do { if ((expr)); else impl__assert_with_message(#expr, message, __FILE__, __LINE__); } while (0)

#define assert_not_null(p) \
    assertm((p), "Except a non-null pointer")

#endif // HEADER_UTILS_H__


typedef int Element;
#define STACK_SIZE 40

typedef struct Stack {
    Element data[STACK_SIZE];
    int top;
} Stack;

Stack*
createStack(void) {
    Stack *p = checked_malloc(sizeof *p);
    p->top = 0;

    return p;
}

bool
StackEmpty(
    Stack stack[static 1]
) {
    assert_not_null(stack);
    return stack->top == 0;
}

bool
Push(
    Stack stack[static 1],
    Element element[static 1]
) {
    assert_not_null(stack);
    // assertm(stack->top != STACK_SIZE, "push on a full stack");
    if (stack->top == STACK_SIZE) {
        return false;
    }

    stack->data[stack->top++] = *element;
    return true;
}

Element*
Pop(
    Stack stack[static 1]
) {
    assert_not_null(stack);

    if (StackEmpty(stack)) {
        return 0;
    }

    stack->top -= 1;
    return stack->data + stack->top;
}

Element*
GetTop(
    Stack stack[static 1]
) {
    assert_not_null(stack);

    if (StackEmpty(stack)) {
        return 0;
    }

    return stack->data + stack->top - 1;
}

void
DestoryStack(
    Stack *stack
) {
    return free(stack);
}

void
testStack(
    Stack *stack
) {
    printf("Stack:");
    for (int i = 0; i < stack->top; i++) {
        printf("%d ", stack->data[i]);
    }
    printf("\n");
}
typedef struct Queue {
    Stack *sequence;
    Stack *reverse;
} Queue;

Queue*
createQueue(void) {
    Queue *p = checked_malloc(sizeof *p);

    p->sequence = createStack();
    p->reverse = createStack();

    return p;
}

bool
QueueEmpty(
    Queue queue[static 1]
) {
    return StackEmpty(queue->sequence)
        && StackEmpty(queue->reverse);
}

bool
InSeqMode(
    Queue queue[static 1]
) {
    return StackEmpty(queue->reverse);
}

void
SwitchMode(
    Queue queue[static 1]
) {
    Stack *src = 0, *dst = 0;
    if (InSeqMode(queue)) {
        src = queue->sequence;
        dst = queue->reverse;
    } else {
        src = queue->reverse;
        dst = queue->sequence;
    }

    for (Element *e = 0; (e = Pop(src)); Push(dst, e))
        /* nothing */;
}

bool
EnQueue(
    Queue queue[static 1],
    Element *element
) {
    if (!InSeqMode(queue)) {
        SwitchMode(queue);
    }

    return Push(queue->sequence, element);
}

Element*
DeQueue(
    Queue queue[static 1]
) {
    if (InSeqMode(queue)) {
        SwitchMode(queue);
    }

    return Pop(queue->reverse);
}

Element*
GetHead(
    Queue queue[static 1]
) {
    if (InSeqMode(queue)) {
        SwitchMode(queue);
    }

    return GetTop(queue->reverse);
}

void
DestoryQueue(
    Queue *queue
) {
    if (queue) {
        DestoryStack(queue->sequence);
        DestoryStack(queue->reverse);
        free(queue);
    }
}

void
testQueue(
    Queue queue[static 1]
) {
    printf("Queue:");
    if (InSeqMode(queue)) {
        for (int i = 0; i < queue->sequence->top; i++) {
            printf("%d ", queue->sequence->data[i]);
        }
    } else {
        for (int i = queue->reverse->top - 1; i >= 0; i--) {
            printf("%d ", queue->reverse->data[i]);
        }
    }
    printf("\n");
}

enum {
    MODE_EN = 4,
    MODE_DE = 5,
    MODE_GH = 6,
    MODE_QE = 7,
};

int main() {
    int mode = -1;
    Queue *queue = createQueue();


    while (scanf("%d", &mode) != EOF && mode != -1) {
        switch (mode) {
            case MODE_EN: {
                int num; scanf("%d", &num);
                while (num --> 0) {
                    int value; scanf("%d", &value);

                    if (EnQueue(queue, &value)) {
                        printf("EnQueue:%d\n", value);
                    } else {
                        puts("EnQueue failed");
                    }

                    testQueue(queue);
                }
            } break;

            case MODE_DE: {
                int num; scanf("%d", &num);
                while (num --> 0) {
                    int *value = DeQueue(queue);

                    if (value) {
                        printf("DeQueue:%d\n", *value);
                    } else {
                        puts("DeQueue failed");
                    }

                    testQueue(queue);
                }
            } break;

            case MODE_GH: {
                int *value = GetHead(queue);
                if (value) {
                    printf("GetHead:%d\n", *value);
                } else {
                    puts("GetHead failed");
                }

                testQueue(queue);
            } break;

            case MODE_QE: {
                printf("The Queue is%s Empty\n", QueueEmpty(queue) ? "" : " not");
                testQueue(queue);
            } break;

            default: assertm(false, "Unknown mode");
        }
    }

    DestoryQueue(queue);

    return 0;
}

stdin的输入为下

4 6 9 8 7 6 5 4
5 20
6
7

拿不到返回JSON

我使用命令行gojudge,开启了grpc,在前端成功向/run post了一段代码,可以在/file下查看到,但是我前端拿不到他的返回Json,前端报错是跨域问题。

Pipe 会无视 copyOut 和 copyOutCached

调用 /run 时,files 里添加的 Pipe stdout 和 stderr,在即便没有添加 copyOut 和 copyOutCached 参数,也会被 copyOut 出来.并且能在请求 /file 时看到两个没有名字的文件,内容为 stdout 和 stderr.

请问一下这是故意这样设计的还是一个 bug?

测试代码:

#!/usr/bin/env node
var WebSocketClient = require('websocket').client;

var client = new WebSocketClient();

client.on('connectFailed', function(error) {
  console.log('Connect Error: ' + error.toString());
});

client.on('connect', function(connection) {
  console.log('WebSocket Client Connected');
  connection.on('error', function(error) {
    console.log("Connection Error: " + error.toString());
  });
  connection.on('close', function() {
    console.log('echo-protocol Connection Closed');
  });
  connection.on('message', function(message) {
    if (message.type === 'utf8') {
      console.log("Received: '" + message.utf8Data + "'");
      connection.close();
    }
  });

  function test() {
    if (connection.connected) {
      connection.sendUTF(
String.raw`{
  "requestId":"hello",
    "cmd": [{
        "args": ["/usr/bin/g++", "a.cc", "-o", "a"],
        "env": ["PATH=/usr/bin:/bin"],
        "files": [{
            "content": ""
        }, {
            "name": "stdout",
            "max": 10240
        }, {
            "name": "stderr",
            "max": 10240
        }],
        "cpuLimit": 10000000000,
        "memoryLimit": 104857600,
        "procLimit": 50,
        "copyIn": {
            "a.cc": {
                "content": "COMPILE_ERROR!!!;\n}"
            }
        },
        "copyOut": [],
        "copyOutCached": []
    }]
}`
      );
    }
  }
  test();
});

client.connect('ws://localhost:5050/ws');

输出:

WebSocket Client Connected
Received: '{"requestId":"hello","results":[{"status":"Nonzero Exit Status","exitStatus":1,"time":11284000,"memory":11886592,"runTime":53288945,"files":{"stderr":"a.cc:1:1: error: 'COMPILE_ERROR' does not name a type\n    1 | COMPILE_ERROR!!!;\n      | ^~~~~~~~~~~~~\na.cc:2:1: error: expected declaration before '}' to ken\n    2 | }\n      | ^\n","stdout":""}}]}'
echo-protocol Connection Closed

请求 /file 的回复:

{"BVS4UU5F":"","MQURLSZU":""}

偶发性编译时间超限

大佬你好,
我们学校的oj使用了大佬开发的go-judge,目前遇到一个问题,想请教一下。这个问题只发生在服务器上,很难复现,遇到的概率可能不到10%。

网页端发送的编译请求如下:

{
    "cmd": [
        {
            "args": [
                "/bin/bash",
                "-c",
                "/usr/bin/g++ Main.cpp -std=c++20 -O2 -DONLINE_JUDGE -w -fmax-errors=1 -lm -o Main"
            ],
            "env": [
                "PATH=/usr/bin:/bin"
            ],
            "files": [
                {
                    "content": ""
                },
                {
                    "name": "stdout",
                    "max": 10240
                },
                {
                    "name": "stderr",
                    "max": 10240
                }
            ],
            "cpuLimit": 10000000000,
            "clockLimit": 20000000000,
            "memoryLimit": 536870912,
            "procLimit": 128,
            "copyIn": {
                "Main.cpp": {
                    "content": "#include<bits/stdc++.h>\nusing namespace std;\nint main()\n{\n\tint a,b;\n\tcin>>a>>b;\n\tcout<<a+b<<endl;\n}"
                }
            },
            "copyOut": [
                "stdout",
                "stderr"
            ],
            "copyOutCached": [
                "Main"
            ]
        }
    ]
}

给定的编译时间是10秒,有很小的概率会返回编译超时,瞬间返回结果,显然并没有达到10秒。

其它信息

  • 我们的实体服务器规格为CPU32核,内存64GB,系统Ubuntu 18.04(部署于256GB固态上),OJ采用docker-compose部署(文件挂载于500GB的机械硬盘上)。
  • OJ网页端启动了8个队列并行向go-jduge发送判题请求,也就是说同一时间最多有8个请求发给go-judge。
  • 在个人电脑上部署系统,无法复现这个问题,所以我猜想是否跟高并发有关?

感谢大佬百忙之中予以指教!

在windows中使用copyOutDir将文件转存时,文件为空(文件大小为0KB)

我在window上运行测试环境,在cmd中启动沙盒,启动参数参数为executorserver_1.6.8_windows_amd64.exe -dir ./test
由于copyOutDir使用相对定位转存文件,同时在windows中的临时目录不容易定位,所以使用了-dir 设置为本地缓存(也测试不使用-dir 参数启动,但转存的文件同样是空(文件大小为0KB))
为了避免可能是因为windows权限的问题,在使用-dir ./test 测试时,已经提前将test文件夹的权限设置为了任何用户都可以读写
也测试过以管理员方式启动cmd,然后启动沙盒,但是发现同样转存的文件为空(文件大小为0KB)

下面提交的参数

{
    "cmd": [
        {
            "args": [
                "D:/JudgeEnvs/Cpp/mingw64/bin/g++",
                "-std=c++14",
                "main.cpp",
                "-o",
                "main.exe"
            ],
            "env": [
                "LANG=en_US.UTF-8",
                "LC_ALL=en_US.UTF-8",
                "LANGUAGE=en_US:en",
                "PATH=D:/JudgeEnvs/Cpp/mingw64/bin"
            ],
            "files": [
                {
                    "content": ""
                },
                {
                    "name": "stdout",
                    "max": 33554432
                },
                {
                    "name": "stderr",
                    "max": 33554432
                }
            ],
            "cpuLimit": 10000000000,
            "clockLimit": 10000000000,
            "memoryLimit": 536870912,
            "procLimit": 128,
            "stackLimit": 268435456,
            "copyIn": {
                "main.cpp": {
                    "content": "#include<iostream>\nusing namespace std;\n\nint main() {\n    string s;\n    cin>>s;\n    cout<<s<<endl;\n    \n    return 0;\n}"
                }
            },
            "copyOut": [
                "stdout",
                "stderr"
            ],
            "copyOutCached": [
            ],
            "copyOutDir": "123456"
        }
    ]
}

返回的参数

[
    {
        "status": "Accepted",
        "exitStatus": 0,
        "time": 359375000,
        "memory": 53260288,
        "runTime": 0,
        "files": {
            "stderr": "",
            "stdout": ""
        }
    }
]

proposal: add detailed error information for file error

Currently, when there's a FileError, it is hard to know which file causes the error and the details about the error.

This proposal is to add more detailed file error information to the response with file name and error type with array field fileError.

interface FileError {
    name: string;
    errorType: FileErrorType
}

enum FileErrorType {
    CopyInNotExists,
    CopyOutNotExists,
    CopyOutLimitExists,
    CopyOutNotRegularFile,
    ...
}

Contact method

Do you have Discord? I'm planning to make a online judge platform and need some help with go-sandbox, can you give me your Discord? Thanks in advance.

运行Python的matplotlib库问题

你好作者,我在沙盒中运行matplotlib时,遇到了如下问题:

一、待评测代码

`
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
data1 = pd.read_csv(r'https://dp.xinchanjiao.com/data/test1.csv')
data2 = pd.read_csv(r'https://dp.xinchanjiao.com/data/test2.csv')
data3 = data1.merge(data2,on='地区',how='left')
print('合并后数据行列数分别为:{}行,{}列。'.format(data3.shape[0],data3.shape[1]))
data3.head(5)#查看合并后数据的前5行
nan_num = data3.isna().sum().sum()

row_duplicated = data3.duplicated().sum()
print(f'重复行总数为:{row_duplicated}')
barh_data = barh_data = data3.groupby('省/自治区').agg({'利润':'sum','销售额':'sum'}).sort_values('利润',ascending=True)
barh_data.head()#查看数据前5行
barh = barh_data.plot(kind='barh',figsize=(16,12),width=0.8)
plt.title('各省市销售额&利润条形图',fontdict={'fontsize':20})
plt.xlabel('金额(元)')
plt.ylabel('省/自治区')
plt.grid()
plt.legend()
plt.show()
tem_data = pd.pivot_table(data=data3,values=['销售额'],index=['地区经理'],columns=['类别'],aggfunc='sum')#使用透视函数筛选数据
tem_data.head()#查看数据前5行
for i in range(tem_data.shape[0]):
tem_data.iloc[i].plot(marker='o',ls='--',figsize=(16,7))
plt.title('地区经理&商品类别销售额折线图',fontsize=20)
plt.xlabel('类别')
plt.ylabel('金额(元)')
plt.legend()
plt.grid()
plt.show()
data4 = data3[(data3['销售额']>1000) & (data3['利润']<0)]
`

二、发送给评测机的JSON

{"cmd":[{"args":["/usr/bin/python3","1.py"],"cpuLimit":1000000000,"files":[{"content":""},{"max":9999999,"name":"stdout"},{"max":9999999,"name":"stderr"}],"realCpuLimit":2000000000,"memoryLimit":104857600,"copyIn":{"1.py":{"content":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\ndata1 = pd.read_csv(r'0.csv') \ndata2 = pd.read_csv(r'1.csv') \ndata3 = data1.merge(data2,on='地区',how='left')\ndata3.head(5)#查看合并后数据的前5行\nnan_num = data3.isna().sum().sum()\nrow_duplicated = data3.duplicated().sum()\nbarh_data = barh_data = data3.groupby('省/自治区').agg({'利润':'sum','销售额':'sum'}).sort_values('利润',ascending=True)\nbarh_data.head()#查看数据前5行\nbarh = barh_data.plot(kind='barh',figsize=(16,12),width=0.8)\nplt.title('各省市销售额&利润条形图',fontdict={'fontsize':20})\nplt.xlabel('金额(元)')\nplt.ylabel('省/自治区')\nplt.grid()\nplt.legend()\nplt.show()\ntem_data = pd.pivot_table(data=data3,values=['销售额'],index=['地区经理'],columns=['类别'],aggfunc='sum')#使用透视函数筛选数据\ntem_data.head()#查看数据前5行\nfor i in range(tem_data.shape[0]):\n tem_data.iloc[i].plot(marker='o',ls='--',figsize=(16,7))\nplt.title('地区经理&商品类别销售额折线图',fontsize=20)\nplt.xlabel('类别')\nplt.ylabel('金额(元)')\nplt.legend()\nplt.grid()\nplt.show()\ndata4 = data3[(data3['销售额']>1000) & (data3['利润']<0)]\n\nprint(data1.shape[0])"},"1.csv":{"content":" #############################内容太长,超出了输入框限制,具体内容在1.py中涉及到的csv文件中################ "}},"env":["PATH=/usr/bin:/bin"],"procLimit":50}]}

三、评测机返回的JSON

[{"status":"Nonzero Exit Status","exitStatus":1,"time":773798045,"memory":47820800,"runTime":458349828,"files":{"stderr":"Traceback (most recent call last):\n File \"/w/1.py\", line 3, in \u003cmodule\u003e\n import matplotlib.pyplot as plt\n File \"/usr/local/lib/python3.10/dist-packages/matplotlib/__init__.py\", line 892, in \u003cmodule\u003e\n dict.update(rcParams, _rc_params_in_file(matplotlib_fname()))\n File \"/usr/local/lib/python3.10/dist-packages/matplotlib/__init__.py\", line 569, in matplotlib_fname\n for fname in gen_candidates():\n File \"/usr/local/lib/python3.10/dist-packages/matplotlib/__init__.py\", line 566, in gen_candidates\n yield os.path.join(get_configdir(), 'matplotlibrc')\n File \"/usr/local/lib/python3.10/dist-packages/matplotlib/__init__.py\", line 275, in wrapper\n ret = func(**kwargs)\n File \"/usr/local/lib/python3.10/dist-packages/matplotlib/__init__.py\", line 512, in get_configdir\n return _get_config_or_cache_dir(_get_xdg_config_dir)\n File \"/usr/local/lib/python3.10/dist-packages/matplotlib/__init__.py\", line 471, in _get_config_or_cache_dir\n configdir = Path(xdg_base_getter(), \"matplotlib\")\n File \"/usr/local/lib/python3.10/dist-packages/matplotlib/__init__.py\", line 452, in _get_xdg_config_dir\n return os.environ.get('XDG_CONFIG_HOME') or str(Path.home() / \".config\")\n File \"/usr/lib/python3.10/pathlib.py\", line 998, in home\n return cls(\"~\").expanduser()\n File \"/usr/lib/python3.10/pathlib.py\", line 1438, in expanduser\n raise RuntimeError(\"Could not determine home directory.\")\nRuntimeError: Could not determine home directory.\n","stdout":""}}]

四、问题分析和尝试

感觉是matplotlib问题,根据提示,百度了一下,配置过如下:
import os os.environ['MPLCONFIGDIR'] = os.getcwd() + "/configs/"
结果返回的是:
[{"status":"Time Limit Exceeded","exitStatus":9,"time":1100516463,"memory":57921536,"runTime":1004221715,"files":{"stderr":"Fontconfig error: Cannot load default config file\n","stdout":""}}]

请问作者及各位使用该沙盒的朋友有没有遇到这种问题,是怎么解决的呢?

Why did the run fail?

I installed Docker on my machine and then called your /run API, but I got this result, why did it fail?

[
-{
"status": "Internal Error",
"exitStatus": 0,
"error": "failed to get environment container: failed to start container operation not permitted",
"time": 0,
"memory": 0
}
]

可不可以添加一个 Status.UnmarshalJSON 方法?

您好作者,可不可以在 cmd/executorserver/model/model.go 中添加一个 Status.UnmarshalJSON 方法,来把字符串再转回枚举?

我在用 go 对 executorserver 提供的 REST API 包装时遇到的问题:没有办法将 API 返回的 json 数据转回 Result。具体原因是无法将 Marshal 出来的 string 重新变成枚举。


你可能会问的问题:

  • Q: 为什么不重新写一个 "MyResult" 结构体,然后写个函数把 API 返回的 json 数据转成 "MyResult"?
  • A: 万一那天这个项目更新,把 model.Result 结构体重写了,我的包装不就出 bug 了吗?我想使我的包装一直兼容这个项目的最新 Release。

启动失败

centos7 kernel:3.10.0-1160.11.1.el7.x86_64
./executorserver-amd64
prefork environment failed container: failed to start container fork/exec /proc/self/exe: invalid argument

proposal: use file to collect output in container on linux

Currently, for pipeCollector, a pipe will be created and the write end will be duplicated into the container process. On the read end, a goroutine will be created to copy the output into a memory buffer. After the proposal #20, the memory buffer will be replaced by a temporary file, but a goroutine is still needed in order to copy the output content.

This proposal is to implement output collector via files in container. A new boolean field pipe will be added to pipeCollector.

interface Collector {
    name: string; // file name in copyOut
    max: number;  // maximum bytes to collect
    pipe: boolean; // collect via pipe (the default value is undetermined now)
}

When pipe is false, a file will be created inside container file system (e.g. /tmp/:tempfilename) and open in write-only mode. The file decriptor will be duplicated to the process and the file will be copied out after execution.

With this change, the container default tmpfs size will be increased (e.g. from 16M -> 128M or 256M) to fit the need. Also, a field outputMax will be added to Cmd to override posix rlimit for output provided by cli arguments.

On the other platform, these field will be ignored.

关于在windows上使用/run进行编译时,出现的文件错误

在windows上使用示例进行编译时,指定了文件的本地存储路径,-dir local_path

请求参数:

{
"cmd":[{"cpuLimit":10000000000,
"copyOutDir":"1",
"env":["G:/mingw64/mingw64/bin"],
"copyOut":["stdout","stderr"],
"args":["G:/mingw64/mingw64/bin/g++.exe","a.cc","-o","a"],
"copyOutCached":["a.cc","a"],
"files":[{"content":""},{"max":10240,"name":"stdout"},{"max":10240,"name":"stderr"}],
"memoryLimit":104857600,
"copyIn":{"a.cc":{"content":"#include <iostream>\nusing namespace std;\nint main() {\nint a, b;\ncin >> a >> b;\ncout << a + b << endl;\n}"}},
"procLimit":50}]
}

但是最后的json编译的返回结果提示如下:

[{
    "memory":0,"error":"The parameter is incorrect.",
    "fileIds":{"a.cc":"6MPFYYGC"},
    "fileError":[{"type":"CopyOutOpen","message":"open C:\\Users\\zzzyc\\AppData\\Local\\Temp\\es1880656414/a: The system cannot find the file specified.","name":"a"}],
    "files":{"stdout":"","stderr":""},
    "time":0,
    "runTime":0,
    "exitStatus":0,
    "status":"Internal Error"
}]

请问该如何修改message中提示的错误,使得可以编译成功呢?
这里在进行编译的envargs均已经修改为本地的g++路径

[Help] Compile and execute submited solution on Windows 10

Hi, I'm trying to compile and execute submited solution on Windows 10. I can compile the solution by sending this to /run

{
  "cmd": [
    {
      "args": [
        "g:\\cygwin64\\bin\\g++.exe",
        "-Wall",
        "-std=c++98",
        "-o",
        "code.exe",
        "foo.cc",
        "-lm"
      ],
      "env": [
        "PATH=d:\\\\Download\\\\ThemisSFX_4\\\\FPC\\\\bin\\\\i386-win32;g:\\\\hydro;g:\\\\cygwin64\\\\bin;\r",
        "HOME=g:\\\\hydro\r",
        ""
      ],
      "files": [
        {
          "content": ""
        },
        {
          "name": "stdout",
          "max": 33554432
        },
        {
          "name": "stderr",
          "max": 33554432
        }
      ],
      "cpuLimit": 16000000000,
      "realCpuLimit": 48000000000,
      "memoryLimit": 536870912,
      "strictMemoryLimit": false,
      "procLimit": 32,
      "copyIn": {
        "foo.cc": {
          "content": "#include <bits/stdc++.h>\r\nusing namespace std;\r\nint a,b;\r\nint main() {\r\n    freopen(\"a+b.in\", \"r\", stdin);\r\n    freopen(\"a+b.out\", \"w\", stdout);\r\n     \r\n    ios::sync_with_stdio(0);\r\n    cin.tie(0);\r\n    cout.tie(0);\r\n    cin >> a;\r\n    cin >> b;\r\n    cout << (a+b);\r\n    return 0;\r\n}"
        }
      },
      "copyOut": [],
      "copyOutCached": [
        "code.exe"
      ]
    }
  ]
}

On Linux, I can pass /w/code to args field to execute the compiled solution. But on Windows I don't know how. I tried setting the output path to something like g:\run\code.exe for code.exe but i get error like below (I run executorserver-amd64.exe as adminstrator and also change permission to Eveyrone for g:\run with Full control )

[{'status':'Nonzero Exit Status','exitStatus':1,'time':1046875000,'memory':75116544,'runTime':0,'files':{'stderr':'/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/ld: cannot open output file g:\\code.exe: Permission denied\ncollect2: error: ld returned 1 exit status\n','stdout':''},'fileError':[{'name':'code.exe','type':'CopyOutOpen','message':'open C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\es4154887469/code.exe: The system cannot find the file specified.'}]}]

Please help me.
Thank a lot.
Regard.

/run接口支持非阻塞吗?

/run接口支持非阻塞吗?比如有个任务需要允许很长时间,服务端并不需要等待它执行结束,而是立即返回。而运行结果,可以在服务端开一个接口在后台监听,或者开一个轮询进程查询结果。请问一下,现在能实现这种方式吗?

feat request: kill task

on a websocket connection, run operation returns a taskId, and allow kill the specific task with id immediately (even when time limit isn't reached)

build cache is required, but could not be located: GOCACHE is not defined and neither $XDG_CACHE_HOME nor $HOME are defined\n

操作系统 docker ubuntu

apt install golang

报错如下

build cache is required, but could not be located: GOCACHE is not defined and neither $XDG_CACHE_HOME nor $HOME are defined\n

参数

{
    "cmd": [
        {
            "args": [
                "/usr/bin/go",
                "build",
                "-o",
                "solution",
                "solution.go"
            ],
            "env": [
                "PATH=/usr/bin:/bin,GOPATH=/w,GOCACHE=/tmp"
            ],
            "files": [
                {
                    "content": ""
                },
                {
                    "name": "stdout",
                    "max": 33554432
                },
                {
                    "name": "stderr",
                    "max": 33554432
                }
            ],
            "cpuLimit": 2000000000000000,
            "clockLimit": 2000000000000000,
            "memoryLimit": 2000000000,
            "procLimit": 128,
            "copyIn": {
                "solution.go": {
                    "content": "package main\nimport \"fmt\"\nfunc main() {\n\tfmt.Printf(\"Hello, World!\")\n}"
                }
            },
            "copyOut": [
                "stdout",
                "stderr"
            ],
            "copyOutCached": [
                "solution"
            ]
        }
    ]
}

执行结果

[
    {
        "status": "Nonzero Exit Status",
        "exitStatus": 1,
        "time": 84176000,
        "memory": 17809408,
        "runTime": 57885751,
        "files": {
            "stderr": "build cache is required, but could not be located: GOCACHE is not defined and neither $XDG_CACHE_HOME nor $HOME are defined\n",
            "stdout": ""
        },
        "fileError": [
            {
                "name": "solution",
                "type": "CopyOutOpen",
                "message": "open solution: no such file or directory"
            }
        ]
    }
]

运行4天之后全部报File Error

以docker容器运行4天之后,突然对所有请求(包括以前正常的请求)都返回File Error,error字段内容:

write /dev/shm/executorserver796031983/JWUUBQBH: no space left on device

重启容器之后恢复正常。

看起来是内存不足,但错误发生时记了一下内存信息,挺充足的:

               total        used        free      shared  buff/cache   available
Mem:            62Gi       8.2Gi       3.9Gi        30Mi        50Gi        53Gi
Swap:           15Gi       0.0Ki        15Gi

由于重启后恢复正常,没有记录下更多信息。请大佬帮忙看下可能是什么问题导致?

出现“execve: start: execve: no such file or directory“错误

以下是我发送和接受的数据,按照 https://goj.ac/submissions 中的命令写的发送数据,但是不知道什么原因发生了错误。
在c/c++中,可以正常使用。

{
	'headers': {
		'Content-type': 'application/json'
	},
	'json': {
		'cmd': [{
			'args': ['/usr/bin/python3', '-c', '"import py_compile; py_compile.compile(\'solution.py\', \'solution.pyc\', doraise=True)"'],
			'env': ['PATH=/usr/bin:/bin'],
			'files': [{
				'content': ''
			}, {
				'name': 'stdout',
				'max': 10240
			}, {
				'name': 'stderr',
				'max': 10240
			}],
			'cpuLimit': 3000000000,
			'memoryLimit': 268435456,
			'procLimit': 50,
			'copyIn': {
				'solution.py': {
					'content': 'a, b = map(int, input().split())\r\nprint(a + b)'
				}
			},
			'copyOut': ['stdout', 'stderr'],
			'copyOutCached': ['solution.py'],
			'copyOutDir': '1'
		}]
	}
}

{
	'status': 'Accepted',
	'exitStatus': 0,
	'time': 18214425,
	'memory': 3575808,
	'runTime': 27775827,
	'files': {
		'stderr': '',
		'stdout': ''
	},
	'fileIds': {
		'solution.py': '43IVBW5NICQAAAHX'
	}
}

{
	'headers': {
		'Content-type': 'application/json'
	},
	'json': {
		'cmd': [{
			'args': ['python3', 'solution.py'],
			'env': ['PATH=/usr/bin:/bin'],
			'files': [{
				'content': ''
			}, {
				'name': 'stdout',
				'max': 10240
			}, {
				'name': 'stderr',
				'max': 10240
			}],
			'cpuLimit': 3000000000,
			'memoryLimit': 268435456,
			'procLimit': 50,
			'strictMemoryLimit': False,
			'copyIn': {
				'solution.py': {
					'fileId': '43IVBW5NICQAAAHX'
				}
			}
		}]
	}
}

{
	'status': 'Internal Error',
	'exitStatus': 0,
	'error': 'execve: start: execve: no such file or directory',
	'time': 217028,
	'memory': 131072,
	'runTime': 0,
	'files': {
		'stderr': '',
		'stdout': ''
	}
}

`

您好,我在执行测试时遇到了错误

首先,感谢您提供的优质开源Code,下面是我的问题:
系统:CentOS 8.2 64位
安装方式:docker run -it --rm --privileged --shm-size=256m -p 5050:5050 criyle/executorserver
执行压力测试通过,使用压力测试的post也能accept
但使用postman测试示例中的单文件编译运行时出错,已安装g++
提交内容:
{
"cmd": [{
"args": ["/usr/bin/g++", "a.cc", "-o", "a"],
"env": ["PATH=/usr/bin:/bin"],
"files": [{
"content": ""
}, {
"name": "stdout",
"max": 10240
}, {
"name": "stderr",
"max": 10240
}],
"cpuLimit": 10000000000,
"memoryLimit": 104857600,
"procLimit": 50,
"copyIn": {
"a.cc": {
"content": "#include \nusing namespace std;\nint main() {\nint a, b;\ncin >> a >> b;\ncout << a + b << endl;\n}"
}
},
"copyOut": ["stdout", "stderr"],
"copyOutCached": ["a.cc", "a"],
"copyOutDir": "1"
}]
}
返回结果:
[
{
"status": "Internal Error",
"exitStatus": 0,
"error": "execve: start: execve: no such file or directory",
"time": 319510,
"memory": 0,
"runTime": 0,
"files": {
"stderr": "",
"stdout": ""
},
"fileIds": {
"a.cc": "C4IBYMMQ"
},
"fileError": [
{
"name": "a",
"type": "CopyOutOpen",
"message": "open a: no such file or directory"
}
]
}
]
使用file接口查询发现没有生成a文件,请问是什么原因或有什么解决方案,劳烦解答,感激不尽!

在用了除 gRPC 外其他传输层时,无法向 sandbox 中添加二进制文件

在使用除 gRPC 外其他传输层时(HTTP / WebSocket / FFI 等)时,数据都是以 JSON 方式传递的,然而 struct CmdFile 里的 Content 被声明称了 *string 类型:

// CmdFile defines file from multiple source including local / memory / cached or pipe collector
type CmdFile struct {
Src *string `json:"src"`
Content *string `json:"content"`
FileID *string `json:"fileId"`
Name *string `json:"name"`
Max *int64 `json:"max"`
Pipe bool `json:"pipe"`
}

也就是说,似乎是没办法把一个二进制文件作为调用 /run 时的 copyIn 直接扔到沙盒里去.我尝试了下面几种方法:

  • 使用 README 中的方式,传一个 Buffer 进去,但是直接返回 json: cannot unmarshal object into Go struct field CmdFile.cmd.files.content of type string
  • 使用 buffer.toString('binary'),这样倒是可以传进沙盒,但是沙盒里面的文件会变,比如一个值(十进制)为 $200$ 的 byte 会变成 $195$$136$ 两个 byte.

如果仅是这样那么问题还不是很大,至少可以通过 file post 先把文件传入沙盒,再用 fileId 来在 cmd 中使用文件.但是 FFI 传输层中的 FileAdd 仍然是接受 JSON 字符串作为参数.也就是说,在使用 FFI 时,这个问题目前无解.


顺便提个建议,由于存在二进制文件,且 JSON 里没有对应 byte 的类型,JSON 不太适合作为这个项目的信息传输格式.在假设把 CmdFile 里的 Content 重构成 []byte 类型后,一个 byte 在 JSON 中会占用四个 byte 的空间(包含三个十进制数位和一个逗号),因此建议采用一些更加适合的格式.需要注意的是,BSON 由于其 16 MB 的最大文档大小,同样也不是一个适合的格式.或许 MessagePack 是一个较优的选择.

关于文件上传api /file POST 上传失败

请问这个上传文件的api /file POST 在上传一个文件时报错

ERROR [email protected]/zap.go:62 http: no such file github.com/gin-contrib/zap.GinzapWithConfig.func1 /home/runner/go/pkg/mod/github.com/gin-contrib/[email protected]/zap.go:62 github.com/gin-gonic/gin.(*Context).Next /home/runner/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:168 github.com/gin-gonic/gin.(*Engine).handleHTTPRequest /home/runner/go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:555 github.com/gin-gonic/gin.(*Engine).ServeHTTP /home/runner/go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:511 net/http.serverHandler.ServeHTTP /opt/hostedtoolcache/go/1.17.7/x64/src/net/http/server.go:2879 net/http.(*conn).serve /opt/hostedtoolcache/go/1.17.7/x64/src/net/http/server.go:1930
这个应该怎么解决。或者说可以提供一个关于文件上传的demo吗,谢谢!

给 grpc.go 中 FileGet 函数中返回的错误加上 code

目前的 FileGet 函数在调用时,如果出现与服务器断开连接和或者是文件不存在,均会返回一个 error。我现在有一份代码,需要将这两种错误区分,所以建议在这里 error return 的时候用 status.Error 包装一下,给它加上一个 codes.NotFound 或者什么的,以便调用时区分是哪一种错误。

func (e *execServer) FileGet(c context.Context, f *pb.FileID) (*pb.FileContent, error) {
name, file := e.fs.Get(f.GetFileID())
r, err := envexec.FileToReader(file)
if err != nil {
return nil, err
}


以及,这个地方由于是删了不存在的文件造成的错误,建议 error code 改成 codes.NotFound

func (e *execServer) FileDelete(c context.Context, f *pb.FileID) (*emptypb.Empty, error) {
ok := e.fs.Remove(f.GetFileID())
if !ok {
return nil, status.Errorf(codes.InvalidArgument, "file id does not exists for %v", f.GetFileID())
}
return &emptypb.Empty{}, nil
}

optional copyOut

当要求选手使用文件IO,但选手未创建文件时会返回File Error,且message无法判断是选手文件丢失还是其他文件丢失(同时返回错误文件名)?

希望允许optional选项,在文件不存在时返回空串或采用其他可辨识方案。

hydro-dev/Hydro#153

java编译后运行出现ClassNotFound的问题

如果代码中有使用了多个类,例如内部类,new一个类,那么编译后会形成多个class文件,例如Main.class, Main$sc.class....,这样的多个文件, copyOutCached很难明确指明每个class的名称,编译后只能返回Main.class的FileId,再次发送Main.class的FileId进行java Main运行的请求,就会出现ClassNotFound的报错,可能新的请求已经不在原来编译的文件夹进行运行了,所以代码中那些类的class文件已经丢失或不在新的请求创建的文件夹里面,那该如何解决这个问题呢?

go 1.19编译失败

用go1.19,编译时执行go build ./cmd/exectorserver命令会出现下面的错误:

# github.com/criyle/go-judge/cmd/executorserver
github.com/criyle/go-sandbox/pkg/forkexec.forkAndExecInChild1: nosplit stack over 792 byte limit
github.com/criyle/go-sandbox/pkg/forkexec.forkAndExecInChild1<1>
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall6<1>
        grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
        24 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall6<1>
        grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
        24 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall6<1>
        grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
        24 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall6<1>
        grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
        24 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall6<1>
        grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
        24 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall6<1>
        grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
        24 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall6<1>
        grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
        24 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall6<1>
        grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
        24 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall6<1>
        grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
        24 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit
    grows 744 bytes, calls syscall.RawSyscall<1>
        grows 72 bytes, calls syscall.RawSyscall6<1>
            grows 72 bytes, calls runtime/internal/syscall.Syscall6<1>
            96 bytes over limit


沙箱网络问题

1、你好,请问下沙箱中能有访问外部网络的开关或者配置吗?我们现在有一个评测场景,通过Python使用pandas读取表格,然后利用评测机验证获取到的数组的值进行正确性验证,而pands读取到的表格在外网上,需要使用pandas的read_excel函数获取,但是现在使用评测机时会报URLError错误,因此想问下能否有办法打开沙盒的外网访问权限。

2、另外想问一下,能否放一下Python评测的示例,现在文档中有c++的示例代码,python的没有,恕我愚钝,没有参透,一直用着go-judge-demo的/api/submit去提交评测,现在想把评测的CPU和内存限制个性化设置,如您能发几个Python的示例,万分感谢!

2022/11/08 03:56:50 prefork environment failed container: failed to start container fork/exec /proc/self/exe: invalid argument

在执行
docker run -it --rm --privileged --shm-size=256m -p 5050:5050 criyle/executorserver
的过程中,我遇到了问题,已经执行了centos7的配置文件命令

下面是日志

[root@host-59-74-224-30 ~]# echo user.max_user_namespaces=10000 >> /etc/sysctl.d/98-userns.conf
[root@host-59-74-224-30 ~]# sysctl -p
net.ipv4.ip_forward = 1
[root@host-59-74-224-30 ~]# echo user.max_user_namespaces=10000 >> /etc/sysctl.d/98-userns.conf
[root@host-59-74-224-30 ~]# docker run -it --rm --privileged --shm-size=256m -p 5050:5050 criyle/executorserver
{"level":"info","ts":1667879810.046213,"caller":"executorserver/main.go:62","msg":"config loaded: &{ContainerInitPath: PreFork:1 TmpFsParam:size=128m,nr_inodes=4k NetShare:false MountConf:mount.yaml SeccompConf:seccomp.yaml Parallelism:16 CgroupPrefix:executor_server ContainerCredStart:0 SrcPrefix: Dir: TimeLimitCheckerInterval:100ms ExtraMemoryLimit:16.0 KiB OutputLimit:256.0 MiB CopyOutLimit:64.0 MiB OpenFileLimit:256 Cpuset: EnableCPURate:false CPUCfsPeriod:100ms FileTimeout:0s HTTPAddr::5050 EnableGRPC:false GRPCAddr::5051 MonitorAddr::5052 AuthToken: EnableDebug:false EnableMetrics:false Release:true Silent:false ForceGCTarget:20.0 MiB ForceGCInterval:5s Version:false}"}
{"level":"info","ts":1667879810.0463336,"caller":"executorserver/main.go:273","msg":"random seed: 2408806125596027837"}
{"level":"info","ts":1667879810.0476985,"caller":"env/env_linux.go:59","msg":"Created container mount at:Mounts: bind[/bin:bin:ro], bind[/lib:lib:ro], bind[/lib64:lib64:ro], bind[/usr:usr:ro], bind[/etc/ld.so.cache:etc/ld.so.cache:ro], bind[/etc/alternatives:etc/alternatives:ro], bind[/dev/null:dev/null:rw], bind[/dev/urandom:dev/urandom:rw], bind[/dev/random:dev/random:rw], bind[/dev/zero:dev/zero:rw], bind[/dev/full:dev/full:rw], tmpfs[w], tmpfs[tmp], proc[ro]"}
{"level":"info","ts":1667879810.0477355,"caller":"env/env_linux.go:76","msg":"Kernel version (3.10) < 4.6, don't unshare cgroup"}
{"level":"info","ts":1667879810.0477455,"caller":"env/env_linux.go:97","msg":"Creating container builder: hostName=executor_server, domainName=executor_server, workDir=/w"}
{"level":"info","ts":1667879810.0478673,"caller":"env/env_linux.go:129","msg":"Test created cgroup builder with: cgroup builder(v1): [cpuset, cpuacct, memory, pids]"}
{"level":"info","ts":1667879810.0675452,"caller":"executorserver/main.go:281","msg":"create 1 prefork containers"}
2022/11/08 03:56:50 prefork environment failed container: failed to start container fork/exec /proc/self/exe: invalid argument

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.