From 9b9a79061848d29bb786ca7c3f3b982205526f85 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilovich Date: Mon, 6 Apr 2026 17:59:26 +0300 Subject: [PATCH] fork bomb handling and gdb support --- .gitea/workflows/judge.yml | 4 +--- runner/process_unix.go | 18 ++++++++++++++++++ runner/process_windows.go | 20 ++++++++++++++++++++ runner/runner.go | 25 ++++++++++++++++++++++++- 4 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 runner/process_unix.go create mode 100644 runner/process_windows.go diff --git a/.gitea/workflows/judge.yml b/.gitea/workflows/judge.yml index 3306ced..305731d 100644 --- a/.gitea/workflows/judge.yml +++ b/.gitea/workflows/judge.yml @@ -2,8 +2,6 @@ name: judge run-name: "Sum tests (${{ inputs.student_url || github.repository }})" on: - push: - pull_request: workflow_dispatch: inputs: student_url: @@ -143,7 +141,7 @@ jobs: # runner auto-detects .exe suffix on Windows judge "$SUITE_FILE" . --json $WRAPPER_ARG > "$GITHUB_WORKSPACE/${REPORT_NAME}.json" || true - judge "$SUITE_FILE" . $WRAPPER_ARG || true + judge "$SUITE_FILE" . $WRAPPER_ARG - name: Upload report if: ${{ always() }} diff --git a/runner/process_unix.go b/runner/process_unix.go new file mode 100644 index 0000000..65d0b54 --- /dev/null +++ b/runner/process_unix.go @@ -0,0 +1,18 @@ +//go:build !windows + +package runner + +import ( + "os/exec" + "syscall" +) + +func setProcessGroup(cmd *exec.Cmd) { + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} +} + +func killProcessGroup(cmd *exec.Cmd) { + if cmd.Process != nil { + syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) + } +} diff --git a/runner/process_windows.go b/runner/process_windows.go new file mode 100644 index 0000000..d53c36d --- /dev/null +++ b/runner/process_windows.go @@ -0,0 +1,20 @@ +//go:build windows + +package runner + +import ( + "os/exec" + "syscall" +) + +func setProcessGroup(cmd *exec.Cmd) { + cmd.SysProcAttr = &syscall.SysProcAttr{ + CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP, + } +} + +func killProcessGroup(cmd *exec.Cmd) { + if cmd.Process != nil { + cmd.Process.Kill() + } +} diff --git a/runner/runner.go b/runner/runner.go index 9dc6324..e1a3c41 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -131,6 +131,7 @@ func (r *Runner) build() (string, error) { cmd := shellCommand(ctx, buildCmd) cmd.Dir = r.cfg.WorkDir + setProcessGroup(cmd) cmd.Env = os.Environ() var out bytes.Buffer @@ -138,6 +139,7 @@ func (r *Runner) build() (string, error) { cmd.Stderr = &out if err := cmd.Run(); err != nil { + killProcessGroup(cmd) return out.String(), fmt.Errorf("build failed: %w\n%s", err, out.String()) } return out.String(), nil @@ -249,8 +251,13 @@ func (r *Runner) runTest(t *dsl.Test) *TestResult { wrapper = t.Wrapper } - cmd := buildExecCmd(ctx, wrapper, r.binary, t.Args) + args := t.Args + if wrapper != "" { + args = absoluteArgs(tmpDir, args) + } + cmd := buildExecCmd(ctx, wrapper, r.binary, args) cmd.Dir = tmpDir + setProcessGroup(cmd) cmd.Env = os.Environ() cmd.Env = append(cmd.Env, "LC_ALL=C", "LANG=C") @@ -271,6 +278,10 @@ func (r *Runner) runTest(t *dsl.Test) *TestResult { runErr := cmd.Run() tr.Elapsed = time.Since(start) + if ctx.Err() == context.DeadlineExceeded { + killProcessGroup(cmd) + } + tr.ActualStdout = normalizeOutput(stdout.String(), r.file) tr.ActualStderr = normalizeOutput(stderr.String(), r.file) @@ -327,6 +338,18 @@ func (r *Runner) runTest(t *dsl.Test) *TestResult { return tr } +func absoluteArgs(dir string, args []string) []string { + out := make([]string, len(args)) + for i, a := range args { + if !filepath.IsAbs(a) { + out[i] = filepath.Join(dir, a) + } else { + out[i] = a + } + } + return out +} + func buildExecCmd(ctx context.Context, wrapper, binary string, args []string) *exec.Cmd { if wrapper == "" { return exec.CommandContext(ctx, binary, args...)