This repository was archived by the owner on Feb 17, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathhelpers_linux.odin
More file actions
71 lines (60 loc) · 1.78 KB
/
helpers_linux.odin
File metadata and controls
71 lines (60 loc) · 1.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#+build linux
package main
import "core:log"
import "core:os"
import "core:strings"
import "core:sys/linux"
@(private)
PIPE_BUF :: 4096
case_should_panic :: proc(fn: panic_fn, fn_arg: any, panic_str: string) -> bool {
stderr_pipe: [2]linux.Fd
if err := linux.pipe2(&stderr_pipe, linux.Open_Flags{}); err != .NONE {
log.errorf("panic_case: failed to create pipe: %v", err)
return false
}
pid, err := linux.fork()
switch {
case err != .NONE:
log.errorf("panic_case: failed to fork: %v", err)
return false
case pid == 0:
// In the child, redirect stderr to the pipe, run the function that
// is supposed to panic, and exit normally.
linux.dup2(stderr_pipe[1], 2)
fn(fn_arg)
os.exit(0)
}
// Parent.
defer linux.close(stderr_pipe[0])
defer linux.close(stderr_pipe[1])
// Wait for the child to terminate, and ensure it terminated
// abnormally (SIGILL/SIGTRAP).
wait_status: u32
linux.wait4(pid, &wait_status, linux.Wait_Options{}, nil)
if !linux.WIFSIGNALED(wait_status) {
log.errorf("panic_case: child did not terminate via signal: %x", wait_status)
return false
}
term_sig := linux.Signal(linux.WTERMSIG(wait_status))
if term_sig != .SIGILL && term_sig != .SIGTRAP {
log.errorf("panic_case: child terminated via wrong signal: %v", term_sig)
return false
}
// Consume the child's stderr output from the pipe buffer.
//
// Note: POSIX requires PIPE_BUF be >= 512 bytes, Linux defaults
// to 4096 bytes. Either is sufficient to buffer output for our
// test cases.
buf: [PIPE_BUF]byte
n, _ := linux.read(stderr_pipe[0], buf[:])
if n == 0 {
log.errorf("panic_case: child stderr empty")
return false
}
s := string(buf[:n])
log.debugf("panic case: child stderr: '%s'", s)
return strings.contains(s, panic_str)
}
can_test_panic :: proc() -> bool {
return true
}