Giter Site home page Giter Site logo

criyle / go-judge Goto Github PK

View Code? Open in Web Editor NEW
398.0 7.0 64.0 881 KB

Sandbox Server in REST / gRPC API. Based on Linux container technologies.

License: MIT License

Go 100.00%
oj golang executor-service cgroup container envexec sandbox online-judge go cgroup2

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  avatar

go-judge's Issues

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

运行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

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

在用了除 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吗,谢谢!

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

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

在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": ""
        }
    }
]

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

首先,感谢您提供的优质开源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.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
}

/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)

关于某段代码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

运行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":""}}]

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

偶发性编译时间超限

大佬你好,
我们学校的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。
  • 在个人电脑上部署系统,无法复现这个问题,所以我猜想是否跟高并发有关?

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

"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"
}
]
}
]

optional copyOut

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

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

hydro-dev/Hydro#153

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":""}

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。

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


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,
    ...
}

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"
            }
        ]
    }
]

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.

出现“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': ''
	}
}

`

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.

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.

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
}
]

启动失败

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

拿不到返回JSON

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

沙箱网络问题

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

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

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');

关于在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.

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.