diff --git a/2026test.sh b/2026test.sh index 6e1baefb..7e6ba25d 100755 --- a/2026test.sh +++ b/2026test.sh @@ -12,6 +12,10 @@ NC='\033[0m' TEST_ROOT="./2026test" OUTPUT_DIR="./2026test_results" COMPILER="./build/bin/compiler" +# 本地开发:自动使用包装器限制内存,防止编译器 bug 触发 OOM +if [[ -x "./scripts/compiler-wrapper.sh" ]]; then + COMPILER="./scripts/compiler-wrapper.sh" +fi VERIFY_SCRIPT="./scripts/verify_asm.sh" TIME_ORI_FILE="$OUTPUT_DIR/time_ori.txt" TIME_OPT_FILE="$OUTPUT_DIR/time_opt.txt" @@ -476,9 +480,9 @@ for file in "${ALL_CASES[@]}"; do set +e if [[ "$OPTIMIZE" == "true" ]]; then - "$COMPILER" -O --emit-asm "$file" > "$asm_file" 2>/dev/null + timeout --signal=KILL "$((TIMEOUT_MS / 1000))" "$COMPILER" -O --emit-asm "$file" > "$asm_file" 2>/dev/null else - "$COMPILER" --emit-asm "$file" > "$asm_file" 2>/dev/null + timeout --signal=KILL "$((TIMEOUT_MS / 1000))" "$COMPILER" --emit-asm "$file" > "$asm_file" 2>/dev/null fi compile_code=$? set -e diff --git a/scripts/compiler-wrapper.sh b/scripts/compiler-wrapper.sh new file mode 100755 index 00000000..cf455b8d --- /dev/null +++ b/scripts/compiler-wrapper.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +# === 编译器资源限制包装器 === +# 比赛提交不包含此机制 + +PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +REAL="$PROJECT_ROOT/build/bin/compiler.real" + +# 如果 build/bin/compiler.real 不存在,尝试 build/bin/compiler +if [[ ! -x "$REAL" ]]; then + if [[ -x "$PROJECT_ROOT/build/bin/compiler" ]] && file "$PROJECT_ROOT/build/bin/compiler" | grep -q 'ELF'; then + REAL="$PROJECT_ROOT/build/bin/compiler" + fi +fi + +if [[ ! -x "$REAL" ]]; then + echo "错误: 编译器二进制不存在" >&2 + echo "提示: 运行 cmake --build build 重新构建" >&2 + exit 1 +fi + +ulimit -S -v 12582912 2>/dev/null || true +exec timeout --signal=KILL 300 "$REAL" "$@" diff --git a/scripts/setup-compiler-wrapper.sh b/scripts/setup-compiler-wrapper.sh new file mode 100644 index 00000000..95c32d55 --- /dev/null +++ b/scripts/setup-compiler-wrapper.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# 编译器包装器恢复脚本 — 每次 cmake --build 后运行此脚本 +# cmake 构建会覆盖 build/bin/compiler 为 ELF 二进制, +# 此脚本将其重命名为 compiler.real 并安装资源限制包装器 +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +BIN_DIR="$SCRIPT_DIR/../build/bin" +COMPILER_BIN="$BIN_DIR/compiler" + +if [[ ! -f "$COMPILER_BIN" ]]; then + echo "错误: $COMPILER_BIN 不存在,请先构建" >&2 + exit 1 +fi + +if file "$COMPILER_BIN" | grep -q 'ELF'; then + echo "检测到 ELF 二进制,安装资源限制包装器..." + mv "$COMPILER_BIN" "$BIN_DIR/compiler.real" + cp "$SCRIPT_DIR/compiler-wrapper.sh" "$COMPILER_BIN" + chmod +x "$COMPILER_BIN" + echo "完成: $COMPILER_BIN 现在是资源限制包装器" +else + echo "包装器已存在,跳过" +fi diff --git a/scripts/verify_asm.sh b/scripts/verify_asm.sh index 0b511835..83a7770a 100755 --- a/scripts/verify_asm.sh +++ b/scripts/verify_asm.sh @@ -35,6 +35,10 @@ if [[ ! -f "$input" ]]; then fi compiler="./build/bin/compiler" +# 本地开发:自动使用包装器限制内存 +if [[ -x "./scripts/compiler-wrapper.sh" ]]; then + compiler="./scripts/compiler-wrapper.sh" +fi if [[ ! -x "$compiler" ]]; then echo "未找到编译器: $compiler ,请先构建。" >&2 exit 1 @@ -131,9 +135,9 @@ expected_file="$input_dir/$stem.out" compile_start=$(get_timestamp_ms) if [[ "$optimize" == true ]]; then - "$compiler" -O --emit-asm "$input" > "$asm_file" + timeout --signal=KILL 300 "$compiler" -O --emit-asm "$input" > "$asm_file" else - "$compiler" --emit-asm "$input" > "$asm_file" + timeout --signal=KILL 300 "$compiler" --emit-asm "$input" > "$asm_file" fi # 记录编译结束时间