tangled
alpha
login
or
join now
dunkirk.sh
/
battleship-arena
1
fork
atom
a geicko-2 based round robin ranking system designed to test c++ battleship submissions
battleship.dunkirk.sh
1
fork
atom
overview
issues
pulls
pipelines
feat: improve error handling
dunkirk.sh
3 months ago
96e63d83
b64871ca
verified
This commit was signed with the committer's
known signature
.
dunkirk.sh
SSH Key Fingerprint:
SHA256:DqcG0RXYExE26KiWo3VxJnsxswN1QNfTBvB+bdSpk80=
+61
-1
2 changed files
expand all
collapse all
unified
split
internal
runner
runner.go
server
web.go
+60
-1
internal/runner/runner.go
···
31
31
ctx, cancel := context.WithTimeout(ctx, time.Duration(timeoutSec)*time.Second)
32
32
defer cancel()
33
33
34
34
+
// Check if systemd-run is available (not on macOS/local dev)
35
35
+
_, err := exec.LookPath("systemd-run")
36
36
+
if err != nil {
37
37
+
// Fallback: run directly without sandbox (development only)
38
38
+
log.Printf("systemd-run not available, running without sandbox: %v", args)
39
39
+
cmd := exec.CommandContext(ctx, args[0], args[1:]...)
40
40
+
output, err := cmd.CombinedOutput()
41
41
+
42
42
+
if ctx.Err() == context.DeadlineExceeded {
43
43
+
return output, fmt.Errorf("command timed out after %d seconds", timeoutSec)
44
44
+
}
45
45
+
46
46
+
return output, err
47
47
+
}
48
48
+
34
49
// Build systemd-run command with security properties
35
50
// Using service unit (not scope) to get access to network/filesystem isolation
36
51
systemdArgs := []string{
···
64
79
// Check for timeout
65
80
if ctx.Err() == context.DeadlineExceeded {
66
81
return output, fmt.Errorf("command timed out after %d seconds", timeoutSec)
82
82
+
}
83
83
+
84
84
+
// Check if process was killed by a signal
85
85
+
if err != nil {
86
86
+
if exitErr, ok := err.(*exec.ExitError); ok {
87
87
+
if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
88
88
+
// Direct execution: check if signaled
89
89
+
if status.Signaled() {
90
90
+
sig := status.Signal()
91
91
+
return output, fmt.Errorf("killed by signal: %s", sig.String())
92
92
+
}
93
93
+
// systemd-run execution: exit code 128+N means killed by signal N
94
94
+
exitCode := status.ExitStatus()
95
95
+
if exitCode >= 128 && exitCode <= 192 {
96
96
+
sigNum := exitCode - 128
97
97
+
sigName := "unknown"
98
98
+
switch sigNum {
99
99
+
case 1: sigName = "SIGHUP"
100
100
+
case 2: sigName = "SIGINT"
101
101
+
case 3: sigName = "SIGQUIT"
102
102
+
case 4: sigName = "SIGILL"
103
103
+
case 5: sigName = "SIGTRAP"
104
104
+
case 6: sigName = "SIGABRT"
105
105
+
case 7: sigName = "SIGBUS"
106
106
+
case 8: sigName = "SIGFPE"
107
107
+
case 9: sigName = "SIGKILL"
108
108
+
case 10: sigName = "SIGUSR1"
109
109
+
case 11: sigName = "SIGSEGV"
110
110
+
case 12: sigName = "SIGUSR2"
111
111
+
case 13: sigName = "SIGPIPE"
112
112
+
case 14: sigName = "SIGALRM"
113
113
+
case 15: sigName = "SIGTERM"
114
114
+
default: sigName = fmt.Sprintf("signal %d", sigNum)
115
115
+
}
116
116
+
return output, fmt.Errorf("killed by %s (exit code %d)", sigName, exitCode)
117
117
+
}
118
118
+
}
119
119
+
}
67
120
}
68
121
69
122
return output, err
···
231
284
output, err = runSandboxed(context.Background(), "run-match", runArgs, 300)
232
285
if err != nil {
233
286
log.Printf("Match execution failed: %v\n%s", err, output)
234
234
-
return 0, 0, 0, fmt.Sprintf("Runtime error: %s (possible crash, timeout, or infinite loop)", strings.TrimSpace(string(output)))
287
287
+
errMsg := strings.TrimSpace(string(output))
288
288
+
if errMsg != "" {
289
289
+
// If there's output, show it along with the exit status
290
290
+
return 0, 0, 0, fmt.Sprintf("Runtime error: %s (%s)", errMsg, err.Error())
291
291
+
}
292
292
+
// If no output, just show the error
293
293
+
return 0, 0, 0, fmt.Sprintf("Runtime error: %s", err.Error())
235
294
}
236
295
237
296
p1, p2, moves := parseMatchOutput(string(output))
+1
internal/server/web.go
···
527
527
528
528
.collapsible-section {
529
529
margin-top: 2rem;
530
530
+
margin-bottom: 2rem;
530
531
background: #1e293b;
531
532
border: 1px solid #334155;
532
533
border-radius: 0.75rem;