From 240080e9d86708c85b27667a4c8cf8aecf863467 Mon Sep 17 00:00:00 2001 From: Toshihiko SHIMOKAWA Date: Tue, 23 Jun 2026 10:25:39 +0900 Subject: [PATCH 1/5] Add per-case test timeout via oj --tle Pass --tle to oj in the test/tf make targets so that infinite loops or overly slow code are killed and reported as TLE instead of hanging. - Default OJ_TLE=4s: AtCoder's limit is 2s, but the dev container can be slower than the judge, so allow headroom to avoid false TLE. - Overridable per task: OJ_TLE=2 am t .java - Document the behavior and override in CLAUDE.md --- CLAUDE.md | 4 ++++ lib/.support/makefile | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 82c5de4..371bbac 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -28,6 +28,9 @@ am t .rs # Rust # 浮動小数点誤差を許容するテスト am tf .java +# タイムアウトを変更してテスト(デフォルト4秒) +OJ_TLE=2 am t .java # 制限時間を2秒に上書き + # コード提出 am s .java # 各言語の拡張子を指定 @@ -81,6 +84,7 @@ makefileで管理(`/root/lib/.support/makefile`へのシンボリックリン - C++ は `am t .cpp` で常に `/judge` ディレクトリ方式(Judge 環境と同じ)でコンパイル・実行されます。問題ディレクトリに `a.out` が生成されないため、クリーンな開発環境を維持できます。 - Elixir は `am t .ex` で常に Mix release(judge 環境と同じ方式)でビルドされます。ビルド時間が短いため、開発効率とjudge環境との完全一致を両立できます。 - JavaScript は `am t .js` で常に64MBスタックサイズ(judge 環境と同じ)で実行されます。デフォルトのNode.jsスタック(約1MB)と異なり、再帰処理でのスタックオーバーフローを防ぎます。 +- `am t` / `am tf` は `oj` の `--tle` により各テストケースを**デフォルト4秒**で打ち切ります(makefile の `OJ_TLE` 変数)。AtCoder の標準制限は2秒ですが、Dev Container は judge より遅い場合があるため誤TLEを避けて余裕を持たせています。無限ループや極端に遅いコードでもハングせず `TLE` と表示されます。問題ごとに変更する場合は `OJ_TLE=2 am t .java` のように環境変数で上書きできます。 ### テンプレート設定 `atcoder-cli-nodejs/config.json`の`default-template`で指定: diff --git a/lib/.support/makefile b/lib/.support/makefile index c8c8ea2..e2f8179 100644 --- a/lib/.support/makefile +++ b/lib/.support/makefile @@ -132,7 +132,11 @@ OJ_SFLAGS = -l 6077 endif OJ = oj -OJ_TFLAGS = -c '$(RUN_TEST)' --ignore-spaces-and-newline +# Per-case time limit (seconds). AtCoder's standard limit is 2s, but the +# dev container can be slower than the judge, so allow extra headroom to +# avoid false TLE. Override per task with e.g. `OJ_TLE=2 am t .java`. +OJ_TLE ?= 4 +OJ_TFLAGS = -c '$(RUN_TEST)' --ignore-spaces-and-newline --tle $(OJ_TLE) OJ_TFLAGS_FLOAT = -e 1e-6 TASK:=$$(basename $(CURDIR)) From ce00cf33d20aab2f72dccc56764e32e26e41075b Mon Sep 17 00:00:00 2001 From: Toshihiko SHIMOKAWA Date: Tue, 23 Jun 2026 10:52:57 +0900 Subject: [PATCH 2/5] Address review: clarify OJ_TLE is a positive integer and OJ_TFLAGS expansion - Note OJ_TLE must be a positive integer (seconds) in makefile and CLAUDE.md - Document why OJ_TFLAGS stays recursively expanded so env override works --- CLAUDE.md | 2 +- lib/.support/makefile | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 371bbac..9984074 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -84,7 +84,7 @@ makefileで管理(`/root/lib/.support/makefile`へのシンボリックリン - C++ は `am t .cpp` で常に `/judge` ディレクトリ方式(Judge 環境と同じ)でコンパイル・実行されます。問題ディレクトリに `a.out` が生成されないため、クリーンな開発環境を維持できます。 - Elixir は `am t .ex` で常に Mix release(judge 環境と同じ方式)でビルドされます。ビルド時間が短いため、開発効率とjudge環境との完全一致を両立できます。 - JavaScript は `am t .js` で常に64MBスタックサイズ(judge 環境と同じ)で実行されます。デフォルトのNode.jsスタック(約1MB)と異なり、再帰処理でのスタックオーバーフローを防ぎます。 -- `am t` / `am tf` は `oj` の `--tle` により各テストケースを**デフォルト4秒**で打ち切ります(makefile の `OJ_TLE` 変数)。AtCoder の標準制限は2秒ですが、Dev Container は judge より遅い場合があるため誤TLEを避けて余裕を持たせています。無限ループや極端に遅いコードでもハングせず `TLE` と表示されます。問題ごとに変更する場合は `OJ_TLE=2 am t .java` のように環境変数で上書きできます。 +- `am t` / `am tf` は `oj` の `--tle` により各テストケースを**デフォルト4秒**で打ち切ります(makefile の `OJ_TLE` 変数)。AtCoder の標準制限は2秒ですが、Dev Container は judge より遅い場合があるため誤TLEを避けて余裕を持たせています。無限ループや極端に遅いコードでもハングせず `TLE` と表示されます。問題ごとに変更する場合は `OJ_TLE=2 am t .java` のように環境変数で上書きできます(秒数は正の整数で指定)。 ### テンプレート設定 `atcoder-cli-nodejs/config.json`の`default-template`で指定: diff --git a/lib/.support/makefile b/lib/.support/makefile index e2f8179..ac753c0 100644 --- a/lib/.support/makefile +++ b/lib/.support/makefile @@ -132,10 +132,13 @@ OJ_SFLAGS = -l 6077 endif OJ = oj -# Per-case time limit (seconds). AtCoder's standard limit is 2s, but the -# dev container can be slower than the judge, so allow extra headroom to -# avoid false TLE. Override per task with e.g. `OJ_TLE=2 am t .java`. +# Per-case time limit, a positive integer number of seconds. AtCoder's +# standard limit is 2s, but the dev container can be slower than the judge, +# so allow extra headroom to avoid false TLE. Override per task with e.g. +# `OJ_TLE=2 am t .java`. OJ_TLE ?= 4 +# Keep OJ_TFLAGS recursively expanded (`=`, not `:=`) so an env override of +# OJ_TLE is honoured at use time. OJ_TFLAGS = -c '$(RUN_TEST)' --ignore-spaces-and-newline --tle $(OJ_TLE) OJ_TFLAGS_FLOAT = -e 1e-6 From 4880a2375babc41558b1e1eabb27f932b56f2582 Mon Sep 17 00:00:00 2001 From: Toshihiko SHIMOKAWA Date: Tue, 23 Jun 2026 16:16:42 +0900 Subject: [PATCH 3/5] Address review: validate OJ_TLE is a positive integer Guard against invalid OJ_TLE values (0, negatives, non-numeric) with a clear make $(error) instead of passing a bad value to oj. OJ_TLE=0 would otherwise make every case TLE, and OJ_TLE=abc would fail deep inside oj. --- lib/.support/makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/.support/makefile b/lib/.support/makefile index ac753c0..81db6c0 100644 --- a/lib/.support/makefile +++ b/lib/.support/makefile @@ -137,6 +137,11 @@ OJ = oj # so allow extra headroom to avoid false TLE. Override per task with e.g. # `OJ_TLE=2 am t .java`. OJ_TLE ?= 4 +# Fail fast on a non-positive-integer OJ_TLE instead of handing a bad value to +# oj (e.g. OJ_TLE=0 would make every case TLE, OJ_TLE=abc errors deep in oj). +ifeq ($(shell echo '$(OJ_TLE)' | grep -Eq '^[1-9][0-9]*$$' && echo ok),) +$(error OJ_TLE must be a positive integer number of seconds, got: '$(OJ_TLE)') +endif # Keep OJ_TFLAGS recursively expanded (`=`, not `:=`) so an env override of # OJ_TLE is honoured at use time. OJ_TFLAGS = -c '$(RUN_TEST)' --ignore-spaces-and-newline --tle $(OJ_TLE) From b54e7758edc9264470e6f6b23064681059432f8f Mon Sep 17 00:00:00 2001 From: Toshihiko SHIMOKAWA Date: Tue, 23 Jun 2026 16:30:28 +0900 Subject: [PATCH 4/5] Address review: drop inaccurate OJ_TFLAGS expansion comment The comment claimed the recursive (=) expansion was needed for env overrides, but OJ_TLE ?= resolves the env value at parse time, so = vs := makes no difference here. Remove the misleading rationale. --- lib/.support/makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/.support/makefile b/lib/.support/makefile index 81db6c0..b87b1f7 100644 --- a/lib/.support/makefile +++ b/lib/.support/makefile @@ -142,8 +142,6 @@ OJ_TLE ?= 4 ifeq ($(shell echo '$(OJ_TLE)' | grep -Eq '^[1-9][0-9]*$$' && echo ok),) $(error OJ_TLE must be a positive integer number of seconds, got: '$(OJ_TLE)') endif -# Keep OJ_TFLAGS recursively expanded (`=`, not `:=`) so an env override of -# OJ_TLE is honoured at use time. OJ_TFLAGS = -c '$(RUN_TEST)' --ignore-spaces-and-newline --tle $(OJ_TLE) OJ_TFLAGS_FLOAT = -e 1e-6 From dc4a0135449eab7abfd3d38c5d7eafb98e442e8c Mon Sep 17 00:00:00 2001 From: Toshihiko SHIMOKAWA Date: Tue, 23 Jun 2026 16:42:03 +0900 Subject: [PATCH 5/5] Address review: validate OJ_TLE with Make built-ins, no shell Replace the shell-based OJ_TLE guard with pure Make string functions so a value containing quotes or shell metacharacters cannot break the command or inject code. Verified in-container: default/4/2 pass, 0/abc/-1 are rejected. --- lib/.support/makefile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/.support/makefile b/lib/.support/makefile index b87b1f7..94006a4 100644 --- a/lib/.support/makefile +++ b/lib/.support/makefile @@ -139,7 +139,16 @@ OJ = oj OJ_TLE ?= 4 # Fail fast on a non-positive-integer OJ_TLE instead of handing a bad value to # oj (e.g. OJ_TLE=0 would make every case TLE, OJ_TLE=abc errors deep in oj). -ifeq ($(shell echo '$(OJ_TLE)' | grep -Eq '^[1-9][0-9]*$$' && echo ok),) +# Validate with Make built-ins only (no shell), so a value containing quotes or +# shell metacharacters cannot break or inject into a command. +# Strip every digit: a non-empty remainder means a non-digit char is present. +OJ_TLE_NONDIGIT := $(strip $(subst 0,,$(subst 1,,$(subst 2,,$(subst 3,,$(subst 4,,$(subst 5,,$(subst 6,,$(subst 7,,$(subst 8,,$(subst 9,,$(OJ_TLE)))))))))))) +# Strip zeros: an empty remainder means the value is empty or all-zero. +OJ_TLE_NONZERO := $(strip $(subst 0,,$(OJ_TLE))) +ifneq ($(OJ_TLE_NONDIGIT),) +$(error OJ_TLE must be a positive integer number of seconds, got: '$(OJ_TLE)') +endif +ifeq ($(OJ_TLE_NONZERO),) $(error OJ_TLE must be a positive integer number of seconds, got: '$(OJ_TLE)') endif OJ_TFLAGS = -c '$(RUN_TEST)' --ignore-spaces-and-newline --tle $(OJ_TLE)