From 9b5c71007ee4d7229bf229107311ea20f0d98a2e Mon Sep 17 00:00:00 2001 From: leo Date: Sat, 8 Aug 2026 01:07:49 +0800 Subject: [PATCH] =?UTF-8?q?fix(judge):=20=E4=BF=AE=E5=A4=8D=20ltp=20?= =?UTF-8?q?=E5=88=A4=E5=88=86=E5=99=A8=E5=81=A5=E5=A3=AE=E6=80=A7=E2=80=94?= =?UTF-8?q?=E2=80=94=E6=97=A5=E5=BF=97=E6=B1=A1=E6=9F=93=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E5=B4=A9=E6=BA=83=E3=80=81=E9=87=8D=E5=A4=8D=20Summary=20?= =?UTF-8?q?=E4=B8=8D=E5=86=8D=E9=87=8D=E5=A4=8D=E8=AE=A1=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit judge_ltp-{musl,glibc}.py 三处防御性修复: 1. 解析前剥离 ANSI 色码。内核把带色日志(如 "\x1b[93m[WARN] ...")混入 测试输出流时,原判分器在 int() 解析处崩溃 (ValueError: invalid literal for int() with base 10: '0\x1b[93m[WARN]'), 导致整场评测中断。 2. Summary 数值解析加防御:无法解析的行跳过而非崩溃(数值位置可能被 交错的内核日志污染)。 3. 每个用例只累计第一份 Summary。部分内核会打印两份相同的 Summary (测试程序自身 + 内核 wrapper 合成),原判分器两份都累加,passed 翻倍。正常输出(每用例一份 Summary,即脚本自带模板的格式)不受影响。 验证:此前必崩的一例评测现已完整解析;其 ltp passed 回落至单份 Summary 口径(约减半),干净的单份 Summary 输入结果不变。 已知局限:判分器信任串口输出中的 RUN 用例名——内核若打印不同名的 假用例(如加序号前缀重复运行、或伪造自定义用例名),判分器无法 区分真实执行与伪造记录,此类问题需复测(隐藏测例)与评审把关。 Co-authored-by: DeepSeek V4 Flash --- kernel/judge/judge_ltp-glibc.py | 16 +++++++++++++++- kernel/judge/judge_ltp-musl.py | 16 +++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/kernel/judge/judge_ltp-glibc.py b/kernel/judge/judge_ltp-glibc.py index dbd5a62..74968ff 100644 --- a/kernel/judge/judge_ltp-glibc.py +++ b/kernel/judge/judge_ltp-glibc.py @@ -1,3 +1,4 @@ +import re import sys import json @@ -42,13 +43,16 @@ def parse_ltp_log(content): current_case = None return_code = None in_summary = False + skip_summary = False for line in lines: + line = re.sub(r'\x1b\[[0-9;]*m', '', line) # strip ANSI color codes so kernel log pollution doesn't crash the judge stripped_line = line.strip() if stripped_line.startswith('RUN LTP CASE'): current_case = stripped_line.split()[-1] summary_data = {'passed': 0, 'failed': 0, 'broken': 0, 'skipped': 0, 'warnings': 0, 'all': 0} + summary_seen = False return_code = None in_summary = False @@ -71,17 +75,27 @@ def parse_ltp_log(content): elif current_case: if stripped_line == 'Summary:': in_summary = True + if summary_seen: + skip_summary = True + continue + summary_seen = True + skip_summary = False continue if in_summary: if not stripped_line: in_summary = False continue + if skip_summary: + continue parts = stripped_line.split() if len(parts) >= 2 and parts[0] in ['passed', 'failed', 'broken', 'skipped', 'warnings']: key = parts[0] - value = int(parts[1]) + m = re.match(r'\d+', parts[1]) + if m is None: + continue # line polluted by interleaved kernel log, skip instead of crash + value = int(m.group()) summary_data[key] += value summary_data['all'] += value diff --git a/kernel/judge/judge_ltp-musl.py b/kernel/judge/judge_ltp-musl.py index dbd5a62..74968ff 100644 --- a/kernel/judge/judge_ltp-musl.py +++ b/kernel/judge/judge_ltp-musl.py @@ -1,3 +1,4 @@ +import re import sys import json @@ -42,13 +43,16 @@ def parse_ltp_log(content): current_case = None return_code = None in_summary = False + skip_summary = False for line in lines: + line = re.sub(r'\x1b\[[0-9;]*m', '', line) # strip ANSI color codes so kernel log pollution doesn't crash the judge stripped_line = line.strip() if stripped_line.startswith('RUN LTP CASE'): current_case = stripped_line.split()[-1] summary_data = {'passed': 0, 'failed': 0, 'broken': 0, 'skipped': 0, 'warnings': 0, 'all': 0} + summary_seen = False return_code = None in_summary = False @@ -71,17 +75,27 @@ def parse_ltp_log(content): elif current_case: if stripped_line == 'Summary:': in_summary = True + if summary_seen: + skip_summary = True + continue + summary_seen = True + skip_summary = False continue if in_summary: if not stripped_line: in_summary = False continue + if skip_summary: + continue parts = stripped_line.split() if len(parts) >= 2 and parts[0] in ['passed', 'failed', 'broken', 'skipped', 'warnings']: key = parts[0] - value = int(parts[1]) + m = re.match(r'\d+', parts[1]) + if m is None: + continue # line polluted by interleaved kernel log, skip instead of crash + value = int(m.group()) summary_data[key] += value summary_data['all'] += value