Skip to content

Commit 43375e7

Browse files
committed
[Backtracing] Fix out-of-process async backtraces.
These weren't working correctly because I made the unwinder call `_swift_task_getCurrent()`, but of course when out-of-process, it calls that in `swift-backtrace`, which is wrong. Remove that for now. While I'm here, I also tweaked the formatting slightly, and I noticed that we were saying that all thunks were also system functions, which seemed unnecessary and odd. Plus there were a couple of extra system functions I added to make the async crash backtraces nicer in friendly mode. rdar://106363539
1 parent dedfe16 commit 43375e7

File tree

5 files changed

+120
-14
lines changed

5 files changed

+120
-14
lines changed

stdlib/public/Backtracing/BacktraceFormatter.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,16 @@ public struct BacktraceFormatter {
654654
// sourceLocation.column is an index in UTF-8 code units in
655655
// `untabified`. We should point at the grapheme cluster that
656656
// contains that UTF-8 index.
657-
let adjustedColumn = max(sourceLocation.column, 1)
657+
let adjustedColumn: Int
658+
if sourceLocation.column > 0 {
659+
adjustedColumn = sourceLocation.column
660+
} else {
661+
if let ndx = code.firstIndex(where: { $0 != " " }) {
662+
adjustedColumn = code.distance(from: code.startIndex, to: ndx) + 1
663+
} else {
664+
adjustedColumn = 1
665+
}
666+
}
658667
let utf8Ndx
659668
= untabified.utf8.index(untabified.utf8.startIndex,
660669
offsetBy: adjustedColumn,

stdlib/public/Backtracing/FramePointerUnwinder.swift

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@
1616

1717
import Swift
1818

19-
// @available(SwiftStdlib 5.1, *)
20-
@_silgen_name("swift_task_getCurrent")
21-
func _getCurrentAsyncTask() -> UnsafeRawPointer?
22-
2319
@_spi(Unwinders)
2420
public struct FramePointerUnwinder<C: Context, M: MemoryReader>: Sequence, IteratorProtocol {
2521
public typealias Context = C
@@ -47,7 +43,7 @@ public struct FramePointerUnwinder<C: Context, M: MemoryReader>: Sequence, Itera
4743
#if (os(macOS) || os(iOS) || os(watchOS)) && (arch(arm64) || arch(arm64_32) || arch(x86_64))
4844
// On Darwin, we borrow a bit of the frame pointer to indicate async
4945
// stack frames
50-
return (storedFp & (1 << 60)) != 0 && _getCurrentAsyncTask() != nil
46+
return (storedFp & (1 << 60)) != 0
5147
#else
5248
return false
5349
#endif

stdlib/public/Backtracing/SymbolicatedBacktrace.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,17 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
148148
if rawName == "start" && imageName == "dyld" {
149149
return true
150150
}
151-
if let location = sourceLocation,
152-
location.line == 0 && location.column == 0 {
151+
if rawName.hasSuffix("5$mainyyFZ")
152+
|| rawName.hasSuffix("5$mainyyYaFZTQ0_")
153+
|| rawName == "_async_MainTQ0_" {
154+
return true
155+
}
156+
if rawName == "__ZL23completeTaskWithClosurePN5swift12AsyncContextEPNS_10SwiftErrorE" && imageName == "libswift_Concurrency.dylib" {
153157
return true
154158
}
155-
if rawName.hasSuffix("5$mainyyFZ") {
159+
if let location = sourceLocation,
160+
location.line == 0 && location.column == 0
161+
&& !_swift_isThunkFunction(rawName) {
156162
return true
157163
}
158164
#endif

test/Backtracing/CrashAsync.swift

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s -parse-as-library -Onone -g -o %t/CrashAsync
3+
// RUN: %target-codesign %t/CrashAsync
4+
// RUN: (env SWIFT_BACKTRACE=enable=yes,cache=no %target-run %t/CrashAsync || true) | %FileCheck %s
5+
// RUN: (env SWIFT_BACKTRACE=preset=friendly,enable=yes,cache=no %target-run %t/CrashAsync || true) | %FileCheck %s --check-prefix FRIENDLY
6+
7+
// UNSUPPORTED: use_os_stdlib
8+
// UNSUPPORTED: back_deployment_runtime
9+
// REQUIRES: executable_test
10+
// REQUIRES: backtracing
11+
// REQUIRES: OS=macosx
12+
13+
@available(SwiftStdlib 5.1, *)
14+
func crash() {
15+
let ptr = UnsafeMutablePointer<Int>(bitPattern: 4)!
16+
ptr.pointee = 42
17+
}
18+
19+
@available(SwiftStdlib 5.1, *)
20+
func level(_ n: Int) async {
21+
if n < 5 {
22+
await level(n + 1)
23+
} else {
24+
crash()
25+
}
26+
}
27+
28+
@available(SwiftStdlib 5.1, *)
29+
@main
30+
struct CrashAsync {
31+
static func main() async {
32+
await level(1)
33+
}
34+
}
35+
36+
// CHECK: *** Program crashed: Bad pointer dereference at 0x{{0+}}4 ***
37+
38+
// CHECK: Thread {{[0-9]+}} crashed:
39+
40+
// CHECK: 0 0x{{[0-9a-f]+}} crash() + {{[0-9]+}} in CrashAsync at {{.*}}/CrashAsync.swift:16:15
41+
// CHECK-NEXT: 1 [ra] 0x{{[0-9a-f]+}} level(_:) + {{[0-9]+}} in CrashAsync at {{.*}}/CrashAsync.swift:24:5
42+
// CHECK-NEXT: 2 [async] 0x{{[0-9a-f]+}} level(_:) in CrashAsync at {{.*}}/CrashAsync.swift:22
43+
// CHECK-NEXT: 3 [async] 0x{{[0-9a-f]+}} level(_:) in CrashAsync at {{.*}}/CrashAsync.swift:22
44+
// CHECK-NEXT: 4 [async] 0x{{[0-9a-f]+}} level(_:) in CrashAsync at {{.*}}/CrashAsync.swift:22
45+
// CHECK-NEXT: 5 [async] 0x{{[0-9a-f]+}} level(_:) in CrashAsync at {{.*}}/CrashAsync.swift:22
46+
// CHECK-NEXT: 6 [async] 0x{{[0-9a-f]+}} static CrashAsync.main() in CrashAsync at {{.*}}/CrashAsync.swift:32
47+
// CHECK-NEXT: 7 [async] [system] 0x{{[0-9a-f]+}} static CrashAsync.$main() in CrashAsync at {{.*}}/<compiler-generated>
48+
// CHECK-NEXT: 8 [async] [system] 0x{{[0-9a-f]+}} async_MainTQ0_ in CrashAsync at {{.*}}/<compiler-generated>
49+
// CHECK-NEXT: 9 [async] [thunk] 0x{{[0-9a-f]+}} thunk for @escaping @convention(thin) @async () -> () in CrashAsync at {{.*}}/<compiler-generated>
50+
// CHECK-NEXT: 10 [async] [thunk] 0x{{[0-9a-f]+}} partial apply for thunk for @escaping @convention(thin) @async () -> () in CrashAsync at {{.*}}/<compiler-generated>
51+
// CHECK-NEXT: 11 [async] [system] 0x{{[0-9a-f]+}} completeTaskWithClosure(swift::AsyncContext*, swift::SwiftError*) in libswift_Concurrency.dylib at {{.*}}/Task.cpp:463
52+
53+
// FRIENDLY: *** Program crashed: Bad pointer dereference at 0x{{0+}}4 ***
54+
55+
// FRIENDLY: Thread {{[0-9]+}} crashed:
56+
57+
// FRIENDLY: 0 crash() + {{[0-9]+}} in CrashAsync at {{.*}}CrashAsync.swift:16:15
58+
59+
// FRIENDLY: 14| func crash() {
60+
// FRIENDLY-NEXT: 15| let ptr = UnsafeMutablePointer<Int>(bitPattern: 4)!
61+
// FRIENDLY-NEXT: * 16| ptr.pointee = 42
62+
// FRIENDLY-NEXT: | ^
63+
// FRIENDLY-NEXT: 17| }
64+
// FRIENDLY-NEXT: 18|
65+
66+
// FRIENDLY: 1 level(_:) + {{[0-9]+}} in CrashAsync at {{.*}}CrashAsync.swift:24:5
67+
68+
// FRIENDLY: 22| await level(n + 1)
69+
// FRIENDLY-NEXT: 23| } else {
70+
// FRIENDLY-NEXT: * 24| crash()
71+
// FRIENDLY-NEXT: | ^
72+
// FRIENDLY-NEXT: 25| }
73+
// FRIENDLY-NEXT: 26| }
74+
75+
// FRIENDLY:2 level(_:) in CrashAsync at {{.*}}CrashAsync.swift:22
76+
77+
// FRIENDLY: 20| func level(_ n: Int) async {
78+
// FRIENDLY-NEXT: 21| if n < 5 {
79+
// FRIENDLY-NEXT: * 22| await level(n + 1)
80+
// FRIENDLY-NEXT: | ^
81+
// FRIENDLY-NEXT: 23| } else {
82+
// FRIENDLY-NEXT: 24| crash()
83+
84+
// FRIENDLY: 3 level(_:) in CrashAsync at {{.*}}CrashAsync.swift:22
85+
// FRIENDLY: 4 level(_:) in CrashAsync at {{.*}}CrashAsync.swift:22
86+
// FRIENDLY: 5 level(_:) in CrashAsync at {{.*}}CrashAsync.swift:22
87+
// FRIENDLY: 6 static CrashAsync.main() in CrashAsync at {{.*}}CrashAsync.swift:32
88+
89+
// FRIENDLY: 30| struct CrashAsync {
90+
// FRIENDLY-NEXT: 31| static func main() async {
91+
// FRIENDLY-NEXT: * 32| await level(1)
92+
// FRIENDLY-NEXT: | ^
93+
// FRIENDLY-NEXT: 33| }
94+
// FRIENDLY-NEXT: 34| }
95+

test/Backtracing/CrashWithThunk.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ struct CrashWithThunk {
3333

3434
// CHECK: Thread 0 crashed:
3535

36-
// CHECK: 0 0x{{[0-9a-f]+}} crash() + {{[0-9]+}} in CrashWithThunk at {{.*}}/CrashWithThunk.swift:20:15
37-
// CHECK-NEXT: 1 [ra] [thunk] [system] 0x{{[0-9a-f]+}} thunk for @escaping @callee_guaranteed () -> () + {{[0-9]+}} in CrashWithThunk at {{.*}}/Backtracing/<compiler-generated>
38-
// CHECK-NEXT: 2 [ra] 0x{{[0-9a-f]+}} static CrashWithThunk.main() + {{[0-9]+}} in CrashWithThunk at {{.*}}/CrashWithThunk.swift:28:9
39-
// CHECK-NEXT: 3 [ra] [system] 0x{{[0-9a-f]+}} static CrashWithThunk.$main() + {{[0-9]+}} in CrashWithThunk at {{.*}}/CrashWithThunk.swift:23:1
40-
// CHECK-NEXT: 4 [ra] [system] 0x{{[0-9a-f]+}} main + {{[0-9]+}} in CrashWithThunk at {{.*}}/CrashWithThunk.swift
36+
// CHECK: 0 0x{{[0-9a-f]+}} crash() + {{[0-9]+}} in CrashWithThunk at {{.*}}/CrashWithThunk.swift:20:15
37+
// CHECK-NEXT: 1 [ra] [thunk] 0x{{[0-9a-f]+}} thunk for @escaping @callee_guaranteed () -> () + {{[0-9]+}} in CrashWithThunk at {{.*}}/Backtracing/<compiler-generated>
38+
// CHECK-NEXT: 2 [ra] 0x{{[0-9a-f]+}} static CrashWithThunk.main() + {{[0-9]+}} in CrashWithThunk at {{.*}}/CrashWithThunk.swift:28:9
39+
// CHECK-NEXT: 3 [ra] [system] 0x{{[0-9a-f]+}} static CrashWithThunk.$main() + {{[0-9]+}} in CrashWithThunk at {{.*}}/CrashWithThunk.swift:23:1
40+
// CHECK-NEXT: 4 [ra] [system] 0x{{[0-9a-f]+}} main + {{[0-9]+}} in CrashWithThunk at {{.*}}/CrashWithThunk.swift
4141

4242
// CHECK: Registers:
4343

0 commit comments

Comments
 (0)