Skip to content

Judge Sandbox

dxx114514-stack edited this page Oct 5, 2026 · 4 revisions

判题与沙箱

判题流程

提交代码 → 限流/提交锁检查 → 进入评测队列 → 编译 → 逐测试点运行 → 计分
                ↘ WebSocket 实时推送状态(pending → compiling → running → 结果)
  • 评测并发:config/judge.txt 缺失时 MAX_THREADS 默认 (CPU 核数 + 1) / 2(最小 1),可由 config/judge.txt 的 MAX_THREADS= 或环境变量 NoldOJ_JUDGE_THREADS 覆盖。
  • 崩溃恢复:启动时 recoverInterruptedSubmissions() 把中断的提交置为系统错误;IDE 残留的 pending/pending_review/compiling/running 中间态同步收敛,避免永远显示「运行中」。
  • 限流:提交 10 次/分钟、IDE 运行 20 次/分钟(可调,见 配置说明)。
  • 提交锁:存在未完成提交时禁止再次提交,超管及特权用户可豁免。

沙箱架构

主要支持平台为 Windows,两种执行模式:

模式 条件 隔离手段
安全沙箱模式(推荐) sandbox/sandbox_runner.exe 存在 Job Object(内存/CPU/进程树限制)+ 受限令牌 + 低完整性级别(Low IL),文件 IO 题目模式降权写入
传统回退模式 非 Windows 平台;或显式 NoldOJ_ALLOW_NO_SANDBOX=1 且运行器缺失(Windows 默认 fail-closed 拒绝判题) 直接 spawn 编译产物;Windows 每 150ms 用 tasklist 轮询内存、超限即杀,另有超时 kill 与 64KB 输出限制兜底;非 Windows 仅超时与输出限制
  • start.bat 每次启动都会从 sandbox/sandbox_runner.cpp 重新编译 sandbox_runner.exe(需要 g++;编译不可用时沿用已有 exe,仍无 exe 则判题 fail-closed);异常发生时启动日志会明确 WARN。
  • 沙箱模式下内存峰值由 Job Object 测量;回退模式在 Windows 上由 tasklist 轮询测量内存(峰值超限即终止,结果标记 MEMORY_LIMIT)。显示 0KB 仅出现在非 Windows 回退或 tasklist 无采样(如进程过早退出)时,不代表回退模式不测内存。
  • Windows 缺 sandbox_runner.exe 时默认 fail-closed 拒绝判题;仅显式设 NoldOJ_ALLOW_NO_SANDBOX=1(不安全,仅限本地开发)才回退传统模式(旧开关 NoldOJ_REQUIRE_RUNNER=1 行为与默认一致,可不再设置)。其余诊断开关(NoldOJ_NO_APPCONTAINER、NoldOJ_FORCE_CONTAINER、NoldOJ_EXEC_MODE、NoldOJ_NO_LOWIL、NoldOJ_NO_RELABEL、NoldOJ_ROOT、NoldOJ_SANDBOX_VERBOSE)见 docs/support.html 的「沙箱环境变量」表。
  • Linux(如 CI)总是走传统回退模式;运行命令由语言配置的 runUnix 决定。
  • Windows 下超时通过 taskkill /F /T 异步杀进程树,其他平台用 SIGKILL。
  • 单次运行最大输出 64KB(sandbox.maxOutputSize),工作目录为系统临时目录,判题后自动清理。

安全基线

  • AI 代码安全审查(可选):提交/IDE 运行前经 LLM 审查,含 14 种提示词注入模式检测,异步执行不阻塞响应;恶意代码可自动封禁。
  • 代码长度限制:128KB(CODE_LENGTH_LIMIT)。
  • 封禁链路:封禁后 Access Token 与 Refresh Token 全拦截,并支持强制登出时间戳。
  • 注册限流:单 IP 每小时 1 次注册。
  • 编译/运行命令与参数经模板替换后不经 shell 拆词执行,杜绝参数注入;多文件 C++ 编译走参数数组直传;单次提交文件数上限 64(executor.js 的 MAX_FILES)。

测试点、子任务与计分

  • 测试点:.in/.out 成对上传(手传、ZIP、批量接口均可)。SPJ 特殊测试脚本由独立 node 子进程在 vm 沙箱中执行(1 秒超时、阻断 require/process),不经过 sandbox_runner.exe。
  • submit_answer 题型:考生提交纯答案(answer_data),判题时直接与预期输出比对,无需编译运行。
  • 输出比较模式:测试点 compare_mode 支持 text_strict / text_relaxed / real_number(配 real_number_tolerance 容差)与 spj(特殊评测)。
  • 子任务(Subtask):测试点分组,组间可配置依赖与聚合策略(sum 求和 / min 取最小 / max 取最大 / min_score 最低分 / max_time 最短时间 / custom 自定义)。
  • 题目级/组级计分脚本:自定义评分逻辑。

计分脚本语法

  • 语句以 ; 分隔;变量以 @ 开头(@total_score、@status1)。
  • 运算:算术 + - * / %,位运算与逻辑运算 and or not xor,比较 == != >= <= > <;条件表达式支持括号。
  • 内置函数:min(a, b)、max(a, b)、abs(a)。
  • 条件语句:
    if 条件; then
        语句;
    else
        语句;
    fi
    
  • 常量:测试点 AC(1)、WA(2)、TLE(3)、MLE(4);Subtask/整题 AC(1)、UNAC(2)。
  • 传入变量:@statusX、@scoreX、@timeX、@memoryX(X 为测试点/Subtask ID)。
  • 需定义变量:@total_score、@final_status、@final_time、@final_memory。

示例:

if (@status4==AC) and (@status3==AC or @status5==AC); then
    @total_score = 30;
    @final_status = AC;
    @final_time = @time4;
    @final_memory = @memory4;
else
    @total_score = 0;
    @final_status = UNAC;
fi
@total_score = min(@score1 + @score2, 30);
@final_time = max(@time1, @time2);

语言配置

默认语言(backend/database/db.js 初始化):

语言 编译命令 运行命令
C gcc -O2 -Wall -o "{exe}" "{src}" "{exe}"
C++ g++ -O2 -Wall -std=c++17 -o "{exe}" "{src}" "{exe}"
Python 3 — python "{src}"
Java javac "{src}" -d "{workdir}" java -cp "{workdir}" Main
JavaScript — node "{src}"

占位符:{src} 源文件、{exe} 可执行文件(Windows 下自动补 .exe)、{workdir} 工作目录。新增/修改语言:超级管理员在「语言」管理页面填写即可(存数据库、热生效)。

相关文档

Clone this wiki locally