Skip to content

Commit 4d57a80

Browse files
committed
[Backtracing][Tests] add unit tests for coloured/uncoloured output
rdar://164624364
1 parent 95d6d43 commit 4d57a80

File tree

4 files changed

+284
-0
lines changed

4 files changed

+284
-0
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#if os(macOS)
2+
internal import Darwin
3+
#elseif canImport(Glibc)
4+
internal import Glibc
5+
#elseif canImport(Musl)
6+
internal import Musl
7+
#endif
8+
9+
func level1() {
10+
level2()
11+
}
12+
13+
func level2() {
14+
level3()
15+
}
16+
17+
func level3() {
18+
level4()
19+
}
20+
21+
func level4() {
22+
level5()
23+
}
24+
25+
func level5() {
26+
print("About to crash")
27+
let ptr = UnsafeMutablePointer<Int>(bitPattern: 4)!
28+
ptr.pointee = 42
29+
}
30+
31+
@main
32+
struct Crash {
33+
static func main() {
34+
print("subprocess stdout is a tty: \(isatty(1))")
35+
print("subprocess stderr is a tty: \(isatty(2))")
36+
level1()
37+
}
38+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s -parse-as-library -Onone -g -o %t/TTYDetection
3+
// RUN: %target-codesign %t/TTYDetection
4+
5+
// RUN: (env SWIFT_BACKTRACE=enable=yes,cache=no %target-run %t/TTYDetection 2> %t/default-output || true) && cat %t/default-output | %FileCheck %s
6+
// RUN: (env SWIFT_BACKTRACE=enable=yes,cache=no,output-to=stderr %target-run %t/TTYDetection 2> %t/stderr-output || true) && cat %t/stderr-output | %FileCheck %s --check-prefix STDERR
7+
// RUN: (env SWIFT_BACKTRACE=enable=yes,cache=no,output-to=stdout %target-run %t/TTYDetection > %t/stdout-output || true) && cat %t/stdout-output | %FileCheck %s --check-prefix STDOUT
8+
9+
10+
// UNSUPPORTED: use_os_stdlib
11+
// UNSUPPORTED: back_deployment_runtime
12+
// UNSUPPORTED: asan
13+
// REQUIRES: executable_test
14+
// REQUIRES: backtracing
15+
// REQUIRES: OS=macosx || OS=linux-gnu
16+
// COM: we should be able to add Windows to this test
17+
18+
func level1() {
19+
level2()
20+
}
21+
22+
func level2() {
23+
level3()
24+
}
25+
26+
func level3() {
27+
level4()
28+
}
29+
30+
func level4() {
31+
level5()
32+
}
33+
34+
func level5() {
35+
print("About to crash")
36+
let ptr = UnsafeMutablePointer<Int>(bitPattern: 4)!
37+
ptr.pointee = 42
38+
}
39+
40+
@main
41+
struct TTYDetection {
42+
static func main() {
43+
level1()
44+
}
45+
}
46+
47+
// CHECK: *** Program crashed: Bad pointer dereference at 0x{{0+}}4 ***
48+
49+
// CHECK: Thread 0 {{(".*" )?}}crashed:
50+
51+
// CHECK: 0 0x{{[0-9a-f]+}} level5() + {{[0-9]+}} in TTYDetection
52+
// CHECK-NEXT: 1 [ra] 0x{{[0-9a-f]+}} level4() + {{[0-9]+}} in TTYDetection
53+
// CHECK-NEXT: 2 [ra] 0x{{[0-9a-f]+}} level3() + {{[0-9]+}} in TTYDetection
54+
// CHECK-NEXT: 3 [ra] 0x{{[0-9a-f]+}} level2() + {{[0-9]+}} in TTYDetection
55+
56+
57+
// STDERR: *** Program crashed: Bad pointer dereference at 0x{{0+}}4 ***
58+
59+
// STDERR: Thread 0 {{(".*" )?}}crashed:
60+
61+
// STDERR: 0 0x{{[0-9a-f]+}} level5() + {{[0-9]+}} in TTYDetection
62+
// STDERR-NEXT: 1 [ra] 0x{{[0-9a-f]+}} level4() + {{[0-9]+}} in TTYDetection
63+
// STDERR-NEXT: 2 [ra] 0x{{[0-9a-f]+}} level3() + {{[0-9]+}} in TTYDetection
64+
// STDERR-NEXT: 3 [ra] 0x{{[0-9a-f]+}} level2() + {{[0-9]+}} in TTYDetection
65+
66+
// STDOUT: *** Program crashed: Bad pointer dereference at 0x{{0+}}4 ***
67+
68+
// STDOUT: Thread 0 {{(".*" )?}}crashed:
69+
70+
// STDOUT: 0 0x{{[0-9a-f]+}} level5() + {{[0-9]+}} in TTYDetection
71+
// STDOUT-NEXT: 1 [ra] 0x{{[0-9a-f]+}} level4() + {{[0-9]+}} in TTYDetection
72+
// STDOUT-NEXT: 2 [ra] 0x{{[0-9a-f]+}} level3() + {{[0-9]+}} in TTYDetection
73+
// STDOUT-NEXT: 3 [ra] 0x{{[0-9a-f]+}} level2() + {{[0-9]+}} in TTYDetection
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %S/Inputs/CrashSubprocess.swift -parse-as-library -Onone -g -o %t/crash
3+
// RUN: %target-codesign %t/crash
4+
5+
// RUN: %target-build-swift %s -o %t/crash-host
6+
7+
// RUN: (env SWIFT_BACKTRACE=enable=yes,cache=no,interactive=no %target-run %t/crash-host %t/crash)| %FileCheck %s
8+
9+
// UNSUPPORTED: use_os_stdlib
10+
// UNSUPPORTED: back_deployment_runtime
11+
// UNSUPPORTED: asan
12+
13+
// REQUIRES: executable_test
14+
// REQUIRES: backtracing
15+
// REQUIRES: OS=linux-gnu || OS=macosx
16+
17+
// COM: this test would need significant rework on Windows/WinSDK, but is not critical function so probably not worth porting the test to that platform
18+
19+
#if os(macOS)
20+
internal import Darwin
21+
#elseif canImport(Glibc)
22+
internal import Glibc
23+
#elseif canImport(Musl)
24+
internal import Musl
25+
#endif
26+
27+
guard CommandLine.arguments.count > 1 else {
28+
fputs("Usage: \(CommandLine.arguments[0]) <path-to-crash>\n", stderr)
29+
exit(1)
30+
}
31+
32+
let crashPath = CommandLine.arguments[1]
33+
34+
// CHECK: host stdout is a tty: 0
35+
print("host stdout is a tty: \(isatty(1))")
36+
// (piped output on linux is fully buffered by default)
37+
fflush(stdout)
38+
39+
// CHECK: host stderr is a tty: 0
40+
print("host stderr is a tty: \(isatty(2))")
41+
fflush(stdout)
42+
43+
var masterFD: Int32 = 0
44+
var slaveFD: Int32 = 0
45+
46+
let slaveName = UnsafeMutablePointer<CChar>.allocate(capacity: 1024)
47+
48+
guard openpty(&masterFD, &slaveFD, slaveName, nil, nil) == 0 else {
49+
perror("openpty")
50+
exit(1)
51+
}
52+
53+
// CHECK: slave is: /dev/{{.+}}
54+
print("slave is: \(String(cString: slaveName))")
55+
slaveName.deallocate()
56+
fflush(stdout)
57+
58+
// try to avoid using Foundation, use Posix primitives instead
59+
var childPid: pid_t = 0
60+
61+
#if os(macOS)
62+
var childFileActions: posix_spawn_file_actions_t?
63+
posix_spawn_file_actions_init(&childFileActions)
64+
posix_spawn_file_actions_adddup2(&childFileActions, slaveFD, STDOUT_FILENO)
65+
posix_spawn_file_actions_adddup2(&childFileActions, slaveFD, STDERR_FILENO)
66+
67+
guard posix_spawn(&childPid, Array<CChar>(crashPath.utf8CString), &childFileActions, nil, nil, environ) == 0 else {
68+
perror("unable to spawn child")
69+
exit(1)
70+
}
71+
72+
posix_spawn_file_actions_destroy(&childFileActions)
73+
74+
#elseif os(Linux)
75+
var childFileActions = posix_spawn_file_actions_t()
76+
posix_spawn_file_actions_init(&childFileActions)
77+
posix_spawn_file_actions_adddup2(&childFileActions, slaveFD, STDOUT_FILENO)
78+
posix_spawn_file_actions_adddup2(&childFileActions, slaveFD, STDERR_FILENO)
79+
80+
var argv: [UnsafeMutablePointer<CChar>?] = [nil]
81+
82+
guard posix_spawn(&childPid, Array<CChar>(crashPath.utf8CString), &childFileActions, nil, argv, environ) == 0 else {
83+
perror("unable to spawn child")
84+
exit(1)
85+
}
86+
87+
posix_spawn_file_actions_destroy(&childFileActions)
88+
89+
#endif
90+
91+
// CHECK: child pid is {{[0-9]+}}
92+
print("child pid is \(childPid)")
93+
fflush(stdout)
94+
95+
// the parent process should now close this FD as it is used by the child for stdout/stderr
96+
close(slaveFD)
97+
98+
// CHECK: subprocess stdout is a tty: 1
99+
// CHECK: subprocess stderr is a tty: 1
100+
101+
// CHECK: About to crash
102+
103+
// CHECK: 💣{{.*}}Program crashed: Bad pointer dereference at 0x{{0+}}4
104+
// CHECK: Thread 0 {{(".*" )?}}crashed:
105+
// CHECK: Backtrace took {{[0-9.]+}}s
106+
107+
// allow the child process time to start, and crash...
108+
sleep(1)
109+
110+
// now read the standard output and error from our master pty
111+
// and write it to our own standard output for scanning by FileCheck
112+
let bufferSize = 4096
113+
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
114+
var bytesRead = read(masterFD, buffer, bufferSize)
115+
116+
while bytesRead > 0 {
117+
write(1, buffer, bytesRead)
118+
bytesRead = read(masterFD, buffer, bufferSize)
119+
}
120+
121+
close(masterFD)
122+
buffer.deallocate()
123+
124+
// CHECK-NOT: child exited with status: 0
125+
var childExitStatus: Int32 = 0
126+
waitpid(childPid, &childExitStatus, 0)
127+
print("child exited with status: \(childExitStatus)")
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s -parse-as-library -Onone -g -o %t/TTYDetection
3+
// RUN: %target-codesign %t/TTYDetection
4+
5+
// RUN: (env SWIFT_BACKTRACE=enable=yes,cache=no,interactive=no %target-run script -reF %t/script-output %t/TTYDetection || true) && cat %t/script-output | %FileCheck %s
6+
7+
8+
// UNSUPPORTED: use_os_stdlib
9+
// UNSUPPORTED: back_deployment_runtime
10+
// UNSUPPORTED: asan
11+
// REQUIRES: executable_test
12+
// REQUIRES: backtracing
13+
// REQUIRES: OS=macosx
14+
// COM: this won't work on Windows, but is not critical function
15+
16+
func level1() {
17+
level2()
18+
}
19+
20+
func level2() {
21+
level3()
22+
}
23+
24+
func level3() {
25+
level4()
26+
}
27+
28+
func level4() {
29+
level5()
30+
}
31+
32+
func level5() {
33+
print("About to crash")
34+
let ptr = UnsafeMutablePointer<Int>(bitPattern: 4)!
35+
ptr.pointee = 42
36+
}
37+
38+
@main
39+
struct TTYDetection {
40+
static func main() {
41+
level1()
42+
}
43+
}
44+
45+
// CHECK: 💣{{.*}}Program crashed: Bad pointer dereference at 0x{{0+}}4
46+
// CHECK: Thread 0 {{(".*" )?}}crashed:

0 commit comments

Comments
 (0)