From 43375e7a23f2bf86e1927bee9b5489833fb239ba Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Tue, 7 Mar 2023 17:02:40 +0000 Subject: [PATCH 1/2] [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 --- .../Backtracing/BacktraceFormatter.swift | 11 ++- .../Backtracing/FramePointerUnwinder.swift | 6 +- .../Backtracing/SymbolicatedBacktrace.swift | 12 ++- test/Backtracing/CrashAsync.swift | 95 +++++++++++++++++++ test/Backtracing/CrashWithThunk.swift | 10 +- 5 files changed, 120 insertions(+), 14 deletions(-) create mode 100644 test/Backtracing/CrashAsync.swift diff --git a/stdlib/public/Backtracing/BacktraceFormatter.swift b/stdlib/public/Backtracing/BacktraceFormatter.swift index 20b38de5398b1..9ac84850e1e13 100644 --- a/stdlib/public/Backtracing/BacktraceFormatter.swift +++ b/stdlib/public/Backtracing/BacktraceFormatter.swift @@ -654,7 +654,16 @@ public struct BacktraceFormatter { // sourceLocation.column is an index in UTF-8 code units in // `untabified`. We should point at the grapheme cluster that // contains that UTF-8 index. - let adjustedColumn = max(sourceLocation.column, 1) + let adjustedColumn: Int + if sourceLocation.column > 0 { + adjustedColumn = sourceLocation.column + } else { + if let ndx = code.firstIndex(where: { $0 != " " }) { + adjustedColumn = code.distance(from: code.startIndex, to: ndx) + 1 + } else { + adjustedColumn = 1 + } + } let utf8Ndx = untabified.utf8.index(untabified.utf8.startIndex, offsetBy: adjustedColumn, diff --git a/stdlib/public/Backtracing/FramePointerUnwinder.swift b/stdlib/public/Backtracing/FramePointerUnwinder.swift index d5cc7b25a61ea..d8232e9be58ee 100644 --- a/stdlib/public/Backtracing/FramePointerUnwinder.swift +++ b/stdlib/public/Backtracing/FramePointerUnwinder.swift @@ -16,10 +16,6 @@ import Swift -// @available(SwiftStdlib 5.1, *) -@_silgen_name("swift_task_getCurrent") -func _getCurrentAsyncTask() -> UnsafeRawPointer? - @_spi(Unwinders) public struct FramePointerUnwinder: Sequence, IteratorProtocol { public typealias Context = C @@ -47,7 +43,7 @@ public struct FramePointerUnwinder: Sequence, Itera #if (os(macOS) || os(iOS) || os(watchOS)) && (arch(arm64) || arch(arm64_32) || arch(x86_64)) // On Darwin, we borrow a bit of the frame pointer to indicate async // stack frames - return (storedFp & (1 << 60)) != 0 && _getCurrentAsyncTask() != nil + return (storedFp & (1 << 60)) != 0 #else return false #endif diff --git a/stdlib/public/Backtracing/SymbolicatedBacktrace.swift b/stdlib/public/Backtracing/SymbolicatedBacktrace.swift index 35c66bf3ca1e1..72d827c156744 100644 --- a/stdlib/public/Backtracing/SymbolicatedBacktrace.swift +++ b/stdlib/public/Backtracing/SymbolicatedBacktrace.swift @@ -148,11 +148,17 @@ public struct SymbolicatedBacktrace: CustomStringConvertible { if rawName == "start" && imageName == "dyld" { return true } - if let location = sourceLocation, - location.line == 0 && location.column == 0 { + if rawName.hasSuffix("5$mainyyFZ") + || rawName.hasSuffix("5$mainyyYaFZTQ0_") + || rawName == "_async_MainTQ0_" { + return true + } + if rawName == "__ZL23completeTaskWithClosurePN5swift12AsyncContextEPNS_10SwiftErrorE" && imageName == "libswift_Concurrency.dylib" { return true } - if rawName.hasSuffix("5$mainyyFZ") { + if let location = sourceLocation, + location.line == 0 && location.column == 0 + && !_swift_isThunkFunction(rawName) { return true } #endif diff --git a/test/Backtracing/CrashAsync.swift b/test/Backtracing/CrashAsync.swift new file mode 100644 index 0000000000000..dce08760d84d9 --- /dev/null +++ b/test/Backtracing/CrashAsync.swift @@ -0,0 +1,95 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -parse-as-library -Onone -g -o %t/CrashAsync +// RUN: %target-codesign %t/CrashAsync +// RUN: (env SWIFT_BACKTRACE=enable=yes,cache=no %target-run %t/CrashAsync || true) | %FileCheck %s +// RUN: (env SWIFT_BACKTRACE=preset=friendly,enable=yes,cache=no %target-run %t/CrashAsync || true) | %FileCheck %s --check-prefix FRIENDLY + +// UNSUPPORTED: use_os_stdlib +// UNSUPPORTED: back_deployment_runtime +// REQUIRES: executable_test +// REQUIRES: backtracing +// REQUIRES: OS=macosx + +@available(SwiftStdlib 5.1, *) +func crash() { + let ptr = UnsafeMutablePointer(bitPattern: 4)! + ptr.pointee = 42 +} + +@available(SwiftStdlib 5.1, *) +func level(_ n: Int) async { + if n < 5 { + await level(n + 1) + } else { + crash() + } +} + +@available(SwiftStdlib 5.1, *) +@main +struct CrashAsync { + static func main() async { + await level(1) + } +} + +// CHECK: *** Program crashed: Bad pointer dereference at 0x{{0+}}4 *** + +// CHECK: Thread {{[0-9]+}} crashed: + +// CHECK: 0 0x{{[0-9a-f]+}} crash() + {{[0-9]+}} in CrashAsync at {{.*}}/CrashAsync.swift:16:15 +// CHECK-NEXT: 1 [ra] 0x{{[0-9a-f]+}} level(_:) + {{[0-9]+}} in CrashAsync at {{.*}}/CrashAsync.swift:24:5 +// CHECK-NEXT: 2 [async] 0x{{[0-9a-f]+}} level(_:) in CrashAsync at {{.*}}/CrashAsync.swift:22 +// CHECK-NEXT: 3 [async] 0x{{[0-9a-f]+}} level(_:) in CrashAsync at {{.*}}/CrashAsync.swift:22 +// CHECK-NEXT: 4 [async] 0x{{[0-9a-f]+}} level(_:) in CrashAsync at {{.*}}/CrashAsync.swift:22 +// CHECK-NEXT: 5 [async] 0x{{[0-9a-f]+}} level(_:) in CrashAsync at {{.*}}/CrashAsync.swift:22 +// CHECK-NEXT: 6 [async] 0x{{[0-9a-f]+}} static CrashAsync.main() in CrashAsync at {{.*}}/CrashAsync.swift:32 +// CHECK-NEXT: 7 [async] [system] 0x{{[0-9a-f]+}} static CrashAsync.$main() in CrashAsync at {{.*}}/ +// CHECK-NEXT: 8 [async] [system] 0x{{[0-9a-f]+}} async_MainTQ0_ in CrashAsync at {{.*}}/ +// CHECK-NEXT: 9 [async] [thunk] 0x{{[0-9a-f]+}} thunk for @escaping @convention(thin) @async () -> () in CrashAsync at {{.*}}/ +// CHECK-NEXT: 10 [async] [thunk] 0x{{[0-9a-f]+}} partial apply for thunk for @escaping @convention(thin) @async () -> () in CrashAsync at {{.*}}/ +// CHECK-NEXT: 11 [async] [system] 0x{{[0-9a-f]+}} completeTaskWithClosure(swift::AsyncContext*, swift::SwiftError*) in libswift_Concurrency.dylib at {{.*}}/Task.cpp:463 + +// FRIENDLY: *** Program crashed: Bad pointer dereference at 0x{{0+}}4 *** + +// FRIENDLY: Thread {{[0-9]+}} crashed: + +// FRIENDLY: 0 crash() + {{[0-9]+}} in CrashAsync at {{.*}}CrashAsync.swift:16:15 + +// FRIENDLY: 14| func crash() { +// FRIENDLY-NEXT: 15| let ptr = UnsafeMutablePointer(bitPattern: 4)! +// FRIENDLY-NEXT: * 16| ptr.pointee = 42 +// FRIENDLY-NEXT: | ^ +// FRIENDLY-NEXT: 17| } +// FRIENDLY-NEXT: 18| + +// FRIENDLY: 1 level(_:) + {{[0-9]+}} in CrashAsync at {{.*}}CrashAsync.swift:24:5 + +// FRIENDLY: 22| await level(n + 1) +// FRIENDLY-NEXT: 23| } else { +// FRIENDLY-NEXT: * 24| crash() +// FRIENDLY-NEXT: | ^ +// FRIENDLY-NEXT: 25| } +// FRIENDLY-NEXT: 26| } + +// FRIENDLY:2 level(_:) in CrashAsync at {{.*}}CrashAsync.swift:22 + +// FRIENDLY: 20| func level(_ n: Int) async { +// FRIENDLY-NEXT: 21| if n < 5 { +// FRIENDLY-NEXT: * 22| await level(n + 1) +// FRIENDLY-NEXT: | ^ +// FRIENDLY-NEXT: 23| } else { +// FRIENDLY-NEXT: 24| crash() + +// FRIENDLY: 3 level(_:) in CrashAsync at {{.*}}CrashAsync.swift:22 +// FRIENDLY: 4 level(_:) in CrashAsync at {{.*}}CrashAsync.swift:22 +// FRIENDLY: 5 level(_:) in CrashAsync at {{.*}}CrashAsync.swift:22 +// FRIENDLY: 6 static CrashAsync.main() in CrashAsync at {{.*}}CrashAsync.swift:32 + +// FRIENDLY: 30| struct CrashAsync { +// FRIENDLY-NEXT: 31| static func main() async { +// FRIENDLY-NEXT: * 32| await level(1) +// FRIENDLY-NEXT: | ^ +// FRIENDLY-NEXT: 33| } +// FRIENDLY-NEXT: 34| } + diff --git a/test/Backtracing/CrashWithThunk.swift b/test/Backtracing/CrashWithThunk.swift index 741a44a1157b9..d448d970845e3 100644 --- a/test/Backtracing/CrashWithThunk.swift +++ b/test/Backtracing/CrashWithThunk.swift @@ -33,11 +33,11 @@ struct CrashWithThunk { // CHECK: Thread 0 crashed: -// CHECK: 0 0x{{[0-9a-f]+}} crash() + {{[0-9]+}} in CrashWithThunk at {{.*}}/CrashWithThunk.swift:20:15 -// CHECK-NEXT: 1 [ra] [thunk] [system] 0x{{[0-9a-f]+}} thunk for @escaping @callee_guaranteed () -> () + {{[0-9]+}} in CrashWithThunk at {{.*}}/Backtracing/ -// CHECK-NEXT: 2 [ra] 0x{{[0-9a-f]+}} static CrashWithThunk.main() + {{[0-9]+}} in CrashWithThunk at {{.*}}/CrashWithThunk.swift:28:9 -// CHECK-NEXT: 3 [ra] [system] 0x{{[0-9a-f]+}} static CrashWithThunk.$main() + {{[0-9]+}} in CrashWithThunk at {{.*}}/CrashWithThunk.swift:23:1 -// CHECK-NEXT: 4 [ra] [system] 0x{{[0-9a-f]+}} main + {{[0-9]+}} in CrashWithThunk at {{.*}}/CrashWithThunk.swift +// CHECK: 0 0x{{[0-9a-f]+}} crash() + {{[0-9]+}} in CrashWithThunk at {{.*}}/CrashWithThunk.swift:20:15 +// CHECK-NEXT: 1 [ra] [thunk] 0x{{[0-9a-f]+}} thunk for @escaping @callee_guaranteed () -> () + {{[0-9]+}} in CrashWithThunk at {{.*}}/Backtracing/ +// CHECK-NEXT: 2 [ra] 0x{{[0-9a-f]+}} static CrashWithThunk.main() + {{[0-9]+}} in CrashWithThunk at {{.*}}/CrashWithThunk.swift:28:9 +// CHECK-NEXT: 3 [ra] [system] 0x{{[0-9a-f]+}} static CrashWithThunk.$main() + {{[0-9]+}} in CrashWithThunk at {{.*}}/CrashWithThunk.swift:23:1 +// CHECK-NEXT: 4 [ra] [system] 0x{{[0-9a-f]+}} main + {{[0-9]+}} in CrashWithThunk at {{.*}}/CrashWithThunk.swift // CHECK: Registers: From 9061d4e874a8aaf9d0a32fca12f7262bc8f4957b Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Wed, 8 Mar 2023 10:56:17 +0000 Subject: [PATCH 2/2] [Backtracing][Tests] Don't demangle in CrashAsync. The CI nodes currently run an older macOS version that can't demangle the async function names. So, to pass PR testing and CI, we'll need to turn demangling off for this test for now. No big deal. rdar://106363539 --- test/Backtracing/CrashAsync.swift | 86 ++++++++++++++++--------------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/test/Backtracing/CrashAsync.swift b/test/Backtracing/CrashAsync.swift index dce08760d84d9..45ad1fccf5da7 100644 --- a/test/Backtracing/CrashAsync.swift +++ b/test/Backtracing/CrashAsync.swift @@ -1,8 +1,12 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift %s -parse-as-library -Onone -g -o %t/CrashAsync // RUN: %target-codesign %t/CrashAsync -// RUN: (env SWIFT_BACKTRACE=enable=yes,cache=no %target-run %t/CrashAsync || true) | %FileCheck %s -// RUN: (env SWIFT_BACKTRACE=preset=friendly,enable=yes,cache=no %target-run %t/CrashAsync || true) | %FileCheck %s --check-prefix FRIENDLY + +// Demangling is disabled for now because older macOS can't demangle async +// function names. We test demangling elsewhere, so this is no big deal. + +// RUN: (env SWIFT_BACKTRACE=enable=yes,demangle=no,cache=no %target-run %t/CrashAsync || true) | %FileCheck %s +// RUN: (env SWIFT_BACKTRACE=preset=friendly,enable=yes,demangle=no,cache=no %target-run %t/CrashAsync || true) | %FileCheck %s --check-prefix FRIENDLY // UNSUPPORTED: use_os_stdlib // UNSUPPORTED: back_deployment_runtime @@ -37,59 +41,59 @@ struct CrashAsync { // CHECK: Thread {{[0-9]+}} crashed: -// CHECK: 0 0x{{[0-9a-f]+}} crash() + {{[0-9]+}} in CrashAsync at {{.*}}/CrashAsync.swift:16:15 -// CHECK-NEXT: 1 [ra] 0x{{[0-9a-f]+}} level(_:) + {{[0-9]+}} in CrashAsync at {{.*}}/CrashAsync.swift:24:5 -// CHECK-NEXT: 2 [async] 0x{{[0-9a-f]+}} level(_:) in CrashAsync at {{.*}}/CrashAsync.swift:22 -// CHECK-NEXT: 3 [async] 0x{{[0-9a-f]+}} level(_:) in CrashAsync at {{.*}}/CrashAsync.swift:22 -// CHECK-NEXT: 4 [async] 0x{{[0-9a-f]+}} level(_:) in CrashAsync at {{.*}}/CrashAsync.swift:22 -// CHECK-NEXT: 5 [async] 0x{{[0-9a-f]+}} level(_:) in CrashAsync at {{.*}}/CrashAsync.swift:22 -// CHECK-NEXT: 6 [async] 0x{{[0-9a-f]+}} static CrashAsync.main() in CrashAsync at {{.*}}/CrashAsync.swift:32 -// CHECK-NEXT: 7 [async] [system] 0x{{[0-9a-f]+}} static CrashAsync.$main() in CrashAsync at {{.*}}/ -// CHECK-NEXT: 8 [async] [system] 0x{{[0-9a-f]+}} async_MainTQ0_ in CrashAsync at {{.*}}/ -// CHECK-NEXT: 9 [async] [thunk] 0x{{[0-9a-f]+}} thunk for @escaping @convention(thin) @async () -> () in CrashAsync at {{.*}}/ -// CHECK-NEXT: 10 [async] [thunk] 0x{{[0-9a-f]+}} partial apply for thunk for @escaping @convention(thin) @async () -> () in CrashAsync at {{.*}}/ -// CHECK-NEXT: 11 [async] [system] 0x{{[0-9a-f]+}} completeTaskWithClosure(swift::AsyncContext*, swift::SwiftError*) in libswift_Concurrency.dylib at {{.*}}/Task.cpp:463 +// CHECK: 0 0x{{[0-9a-f]+}} _$s10CrashAsync5crashyyF + {{[0-9]+}} in CrashAsync at {{.*}}/CrashAsync.swift:20:15 +// CHECK-NEXT: 1 [ra] 0x{{[0-9a-f]+}} _$s10CrashAsync5levelyySiYaFTY0_ + {{[0-9]+}} in CrashAsync at {{.*}}/CrashAsync.swift:28:5 +// CHECK-NEXT: 2 [async] 0x{{[0-9a-f]+}} _$s10CrashAsync5levelyySiYaFTQ1_ in CrashAsync at {{.*}}/CrashAsync.swift:26 +// CHECK-NEXT: 3 [async] 0x{{[0-9a-f]+}} _$s10CrashAsync5levelyySiYaFTQ1_ in CrashAsync at {{.*}}/CrashAsync.swift:26 +// CHECK-NEXT: 4 [async] 0x{{[0-9a-f]+}} _$s10CrashAsync5levelyySiYaFTQ1_ in CrashAsync at {{.*}}/CrashAsync.swift:26 +// CHECK-NEXT: 5 [async] 0x{{[0-9a-f]+}} _$s10CrashAsync5levelyySiYaFTQ1_ in CrashAsync at {{.*}}/CrashAsync.swift:26 +// CHECK-NEXT: 6 [async] 0x{{[0-9a-f]+}} _$s10CrashAsyncAAV4mainyyYaFZTQ0_ in CrashAsync at {{.*}}/CrashAsync.swift:36 +// CHECK-NEXT: 7 [async] [system] 0x{{[0-9a-f]+}} _$s10CrashAsyncAAV5$mainyyYaFZTQ0_ in CrashAsync at {{.*}}/ +// CHECK-NEXT: 8 [async] [system] 0x{{[0-9a-f]+}} _async_MainTQ0_ in CrashAsync at {{.*}}/ +// CHECK-NEXT: 9 [async] [thunk] 0x{{[0-9a-f]+}} _$sIetH_yts5Error_pIegHrzo_TRTQ0_ in CrashAsync at {{.*}}/ +// CHECK-NEXT: 10 [async] [thunk] 0x{{[0-9a-f]+}} _$sIetH_yts5Error_pIegHrzo_TRTATQ0_ in CrashAsync at {{.*}}/ +// CHECK-NEXT: 11 [async] [system] 0x{{[0-9a-f]+}} __ZL23completeTaskWithClosurePN5swift12AsyncContextEPNS_10SwiftErrorE in libswift_Concurrency.dylib at {{.*}}/Task.cpp:463 // FRIENDLY: *** Program crashed: Bad pointer dereference at 0x{{0+}}4 *** // FRIENDLY: Thread {{[0-9]+}} crashed: -// FRIENDLY: 0 crash() + {{[0-9]+}} in CrashAsync at {{.*}}CrashAsync.swift:16:15 +// FRIENDLY: 0 _$s10CrashAsync5crashyyF + {{[0-9]+}} in CrashAsync at {{.*}}CrashAsync.swift:20:15 -// FRIENDLY: 14| func crash() { -// FRIENDLY-NEXT: 15| let ptr = UnsafeMutablePointer(bitPattern: 4)! -// FRIENDLY-NEXT: * 16| ptr.pointee = 42 +// FRIENDLY: 18| func crash() { +// FRIENDLY-NEXT: 19| let ptr = UnsafeMutablePointer(bitPattern: 4)! +// FRIENDLY-NEXT: * 20| ptr.pointee = 42 // FRIENDLY-NEXT: | ^ -// FRIENDLY-NEXT: 17| } -// FRIENDLY-NEXT: 18| +// FRIENDLY-NEXT: 21| } +// FRIENDLY-NEXT: 22| -// FRIENDLY: 1 level(_:) + {{[0-9]+}} in CrashAsync at {{.*}}CrashAsync.swift:24:5 +// FRIENDLY: 1 _$s10CrashAsync5levelyySiYaFTY0_ + {{[0-9]+}} in CrashAsync at {{.*}}CrashAsync.swift:28:5 -// FRIENDLY: 22| await level(n + 1) -// FRIENDLY-NEXT: 23| } else { -// FRIENDLY-NEXT: * 24| crash() +// FRIENDLY: 26| await level(n + 1) +// FRIENDLY-NEXT: 27| } else { +// FRIENDLY-NEXT: * 28| crash() // FRIENDLY-NEXT: | ^ -// FRIENDLY-NEXT: 25| } -// FRIENDLY-NEXT: 26| } +// FRIENDLY-NEXT: 29| } +// FRIENDLY-NEXT: 30| } -// FRIENDLY:2 level(_:) in CrashAsync at {{.*}}CrashAsync.swift:22 +// FRIENDLY:2 _$s10CrashAsync5levelyySiYaFTQ1_ in CrashAsync at {{.*}}CrashAsync.swift:26 -// FRIENDLY: 20| func level(_ n: Int) async { -// FRIENDLY-NEXT: 21| if n < 5 { -// FRIENDLY-NEXT: * 22| await level(n + 1) +// FRIENDLY: 24| func level(_ n: Int) async { +// FRIENDLY-NEXT: 25| if n < 5 { +// FRIENDLY-NEXT: * 26| await level(n + 1) // FRIENDLY-NEXT: | ^ -// FRIENDLY-NEXT: 23| } else { -// FRIENDLY-NEXT: 24| crash() +// FRIENDLY-NEXT: 27| } else { +// FRIENDLY-NEXT: 28| crash() -// FRIENDLY: 3 level(_:) in CrashAsync at {{.*}}CrashAsync.swift:22 -// FRIENDLY: 4 level(_:) in CrashAsync at {{.*}}CrashAsync.swift:22 -// FRIENDLY: 5 level(_:) in CrashAsync at {{.*}}CrashAsync.swift:22 -// FRIENDLY: 6 static CrashAsync.main() in CrashAsync at {{.*}}CrashAsync.swift:32 +// FRIENDLY: 3 _$s10CrashAsync5levelyySiYaFTQ1_ in CrashAsync at {{.*}}CrashAsync.swift:26 +// FRIENDLY: 4 _$s10CrashAsync5levelyySiYaFTQ1_ in CrashAsync at {{.*}}CrashAsync.swift:26 +// FRIENDLY: 5 _$s10CrashAsync5levelyySiYaFTQ1_ in CrashAsync at {{.*}}CrashAsync.swift:26 +// FRIENDLY: 6 _$s10CrashAsyncAAV4mainyyYaFZTQ0_ in CrashAsync at {{.*}}CrashAsync.swift:36 -// FRIENDLY: 30| struct CrashAsync { -// FRIENDLY-NEXT: 31| static func main() async { -// FRIENDLY-NEXT: * 32| await level(1) +// FRIENDLY: 34| struct CrashAsync { +// FRIENDLY-NEXT: 35| static func main() async { +// FRIENDLY-NEXT: * 36| await level(1) // FRIENDLY-NEXT: | ^ -// FRIENDLY-NEXT: 33| } -// FRIENDLY-NEXT: 34| } +// FRIENDLY-NEXT: 37| } +// FRIENDLY-NEXT: 38| }