Skip to content

Commit 3211f68

Browse files
authored
Merge pull request #64178 from al45tair/eng/PR-106363539
[Backtracing] Fix out-of-process async backtraces.
2 parents f80d072 + 9061d4e commit 3211f68

File tree

5 files changed

+124
-14
lines changed

5 files changed

+124
-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: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
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+
5+
// Demangling is disabled for now because older macOS can't demangle async
6+
// function names. We test demangling elsewhere, so this is no big deal.
7+
8+
// RUN: (env SWIFT_BACKTRACE=enable=yes,demangle=no,cache=no %target-run %t/CrashAsync || true) | %FileCheck %s
9+
// RUN: (env SWIFT_BACKTRACE=preset=friendly,enable=yes,demangle=no,cache=no %target-run %t/CrashAsync || true) | %FileCheck %s --check-prefix FRIENDLY
10+
11+
// UNSUPPORTED: use_os_stdlib
12+
// UNSUPPORTED: back_deployment_runtime
13+
// REQUIRES: executable_test
14+
// REQUIRES: backtracing
15+
// REQUIRES: OS=macosx
16+
17+
@available(SwiftStdlib 5.1, *)
18+
func crash() {
19+
let ptr = UnsafeMutablePointer<Int>(bitPattern: 4)!
20+
ptr.pointee = 42
21+
}
22+
23+
@available(SwiftStdlib 5.1, *)
24+
func level(_ n: Int) async {
25+
if n < 5 {
26+
await level(n + 1)
27+
} else {
28+
crash()
29+
}
30+
}
31+
32+
@available(SwiftStdlib 5.1, *)
33+
@main
34+
struct CrashAsync {
35+
static func main() async {
36+
await level(1)
37+
}
38+
}
39+
40+
// CHECK: *** Program crashed: Bad pointer dereference at 0x{{0+}}4 ***
41+
42+
// CHECK: Thread {{[0-9]+}} crashed:
43+
44+
// CHECK: 0 0x{{[0-9a-f]+}} _$s10CrashAsync5crashyyF + {{[0-9]+}} in CrashAsync at {{.*}}/CrashAsync.swift:20:15
45+
// CHECK-NEXT: 1 [ra] 0x{{[0-9a-f]+}} _$s10CrashAsync5levelyySiYaFTY0_ + {{[0-9]+}} in CrashAsync at {{.*}}/CrashAsync.swift:28:5
46+
// CHECK-NEXT: 2 [async] 0x{{[0-9a-f]+}} _$s10CrashAsync5levelyySiYaFTQ1_ in CrashAsync at {{.*}}/CrashAsync.swift:26
47+
// CHECK-NEXT: 3 [async] 0x{{[0-9a-f]+}} _$s10CrashAsync5levelyySiYaFTQ1_ in CrashAsync at {{.*}}/CrashAsync.swift:26
48+
// CHECK-NEXT: 4 [async] 0x{{[0-9a-f]+}} _$s10CrashAsync5levelyySiYaFTQ1_ in CrashAsync at {{.*}}/CrashAsync.swift:26
49+
// CHECK-NEXT: 5 [async] 0x{{[0-9a-f]+}} _$s10CrashAsync5levelyySiYaFTQ1_ in CrashAsync at {{.*}}/CrashAsync.swift:26
50+
// CHECK-NEXT: 6 [async] 0x{{[0-9a-f]+}} _$s10CrashAsyncAAV4mainyyYaFZTQ0_ in CrashAsync at {{.*}}/CrashAsync.swift:36
51+
// CHECK-NEXT: 7 [async] [system] 0x{{[0-9a-f]+}} _$s10CrashAsyncAAV5$mainyyYaFZTQ0_ in CrashAsync at {{.*}}/<compiler-generated>
52+
// CHECK-NEXT: 8 [async] [system] 0x{{[0-9a-f]+}} _async_MainTQ0_ in CrashAsync at {{.*}}/<compiler-generated>
53+
// CHECK-NEXT: 9 [async] [thunk] 0x{{[0-9a-f]+}} _$sIetH_yts5Error_pIegHrzo_TRTQ0_ in CrashAsync at {{.*}}/<compiler-generated>
54+
// CHECK-NEXT: 10 [async] [thunk] 0x{{[0-9a-f]+}} _$sIetH_yts5Error_pIegHrzo_TRTATQ0_ in CrashAsync at {{.*}}/<compiler-generated>
55+
// CHECK-NEXT: 11 [async] [system] 0x{{[0-9a-f]+}} __ZL23completeTaskWithClosurePN5swift12AsyncContextEPNS_10SwiftErrorE in libswift_Concurrency.dylib at {{.*}}/Task.cpp:463
56+
57+
// FRIENDLY: *** Program crashed: Bad pointer dereference at 0x{{0+}}4 ***
58+
59+
// FRIENDLY: Thread {{[0-9]+}} crashed:
60+
61+
// FRIENDLY: 0 _$s10CrashAsync5crashyyF + {{[0-9]+}} in CrashAsync at {{.*}}CrashAsync.swift:20:15
62+
63+
// FRIENDLY: 18| func crash() {
64+
// FRIENDLY-NEXT: 19| let ptr = UnsafeMutablePointer<Int>(bitPattern: 4)!
65+
// FRIENDLY-NEXT: * 20| ptr.pointee = 42
66+
// FRIENDLY-NEXT: | ^
67+
// FRIENDLY-NEXT: 21| }
68+
// FRIENDLY-NEXT: 22|
69+
70+
// FRIENDLY: 1 _$s10CrashAsync5levelyySiYaFTY0_ + {{[0-9]+}} in CrashAsync at {{.*}}CrashAsync.swift:28:5
71+
72+
// FRIENDLY: 26| await level(n + 1)
73+
// FRIENDLY-NEXT: 27| } else {
74+
// FRIENDLY-NEXT: * 28| crash()
75+
// FRIENDLY-NEXT: | ^
76+
// FRIENDLY-NEXT: 29| }
77+
// FRIENDLY-NEXT: 30| }
78+
79+
// FRIENDLY:2 _$s10CrashAsync5levelyySiYaFTQ1_ in CrashAsync at {{.*}}CrashAsync.swift:26
80+
81+
// FRIENDLY: 24| func level(_ n: Int) async {
82+
// FRIENDLY-NEXT: 25| if n < 5 {
83+
// FRIENDLY-NEXT: * 26| await level(n + 1)
84+
// FRIENDLY-NEXT: | ^
85+
// FRIENDLY-NEXT: 27| } else {
86+
// FRIENDLY-NEXT: 28| crash()
87+
88+
// FRIENDLY: 3 _$s10CrashAsync5levelyySiYaFTQ1_ in CrashAsync at {{.*}}CrashAsync.swift:26
89+
// FRIENDLY: 4 _$s10CrashAsync5levelyySiYaFTQ1_ in CrashAsync at {{.*}}CrashAsync.swift:26
90+
// FRIENDLY: 5 _$s10CrashAsync5levelyySiYaFTQ1_ in CrashAsync at {{.*}}CrashAsync.swift:26
91+
// FRIENDLY: 6 _$s10CrashAsyncAAV4mainyyYaFZTQ0_ in CrashAsync at {{.*}}CrashAsync.swift:36
92+
93+
// FRIENDLY: 34| struct CrashAsync {
94+
// FRIENDLY-NEXT: 35| static func main() async {
95+
// FRIENDLY-NEXT: * 36| await level(1)
96+
// FRIENDLY-NEXT: | ^
97+
// FRIENDLY-NEXT: 37| }
98+
// FRIENDLY-NEXT: 38| }
99+

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)