From 49c4c3a0089feaaa70eb807dd60bb84b79156a8a Mon Sep 17 00:00:00 2001 From: Maciek Grzybowski Date: Tue, 29 Mar 2022 15:42:55 +0200 Subject: [PATCH 1/2] RUMM-2025 Filter out unrecognized trailing stack frame in `error.stack` (only if the frame has no library base address read). --- .../DDCrashReportExporter.swift | 19 +++++++- .../DDCrashReportExporterTests.swift | 43 +++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/Sources/DatadogCrashReporting/PLCrashReporterIntegration/DDCrashReportExporter.swift b/Sources/DatadogCrashReporting/PLCrashReporterIntegration/DDCrashReportExporter.swift index 4e243f8c1f..5d3f8e46b9 100644 --- a/Sources/DatadogCrashReporting/PLCrashReporterIntegration/DDCrashReportExporter.swift +++ b/Sources/DatadogCrashReporting/PLCrashReporterIntegration/DDCrashReportExporter.swift @@ -122,7 +122,22 @@ internal struct DDCrashReportExporter { return unavailable // should never be reached } - return string(from: stackFrames) + return string(from: sanitized(stackFrames: stackFrames)) + } + + // MARK: - Sanitizing + + private func sanitized(stackFrames: [StackFrame]) -> [StackFrame] { + guard let lastFrame = stackFrames.last else { + return stackFrames + } + + // RUMM-2025: Often the last frame has no library name nor its base address. This results with + // producing malformed frame, e.g. `XX ??? 0x00000001045f0250 0x000000000 + 4368302672` + // which can't be symbolicated. To make it cleaner in UI and to avoid BE symbolication errors, we filter + // out such trailing frame. Ref.: https://github.com/microsoft/plcrashreporter/issues/193 + let sanitizedFrames = lastFrame.libraryBaseAddress == nil ? stackFrames.dropLast() : stackFrames + return sanitizedFrames } // MARK: - Exporting threads and binary images @@ -131,7 +146,7 @@ internal struct DDCrashReportExporter { return crashReport.threads.map { thread in return DDCrashReport.Thread( name: "Thread \(thread.threadNumber)", - stack: string(from: thread.stackFrames), + stack: string(from: thread.stackFrames), // we don't sanitize frames in `error.threads[]` crashed: thread.crashed, state: nil // TODO: RUMM-1462 Send registers state for crashed thread ) diff --git a/Tests/DatadogCrashReportingTests/PLCrashReporterIntegration/DDCrashReportExporterTests.swift b/Tests/DatadogCrashReportingTests/PLCrashReporterIntegration/DDCrashReportExporterTests.swift index 31ac798ab3..000c3d4e94 100644 --- a/Tests/DatadogCrashReportingTests/PLCrashReporterIntegration/DDCrashReportExporterTests.swift +++ b/Tests/DatadogCrashReportingTests/PLCrashReporterIntegration/DDCrashReportExporterTests.swift @@ -204,6 +204,26 @@ class DDCrashReportExporterTests: XCTestCase { XCTAssertEqual(actualStack, expectedStack) } + func testWhenLastFrameInTheStackHasNoLibraryBaseAddress_itIsFilteredOut() { + let stackFrames: [StackFrame] = [ + .init(number: 0, libraryName: "Foo", libraryBaseAddress: 100, instructionPointer: 102), + .init(number: 1, libraryName: "Foo", libraryBaseAddress: 100, instructionPointer: 112), + .init(number: 2, libraryName: "Bizz", libraryBaseAddress: 400, instructionPointer: 432), + .init(number: 3, libraryName: "Bizz", libraryBaseAddress: nil, instructionPointer: 432), + ] + + crashReport.exceptionInfo = .init(name: .mockAny(), reason: .mockAny(), stackFrames: stackFrames) + + let actualStack = exporter.export(crashReport).stack + let expectedStack = """ + 0 Foo 0x0000000000000066 0x64 + 2 + 1 Foo 0x0000000000000070 0x64 + 12 + 2 Bizz 0x00000000000001b0 0x190 + 32 + """ + + XCTAssertEqual(actualStack, expectedStack) + } + // MARK: - Formatting threads func testExportingThreads() { @@ -251,6 +271,29 @@ class DDCrashReportExporterTests: XCTestCase { XCTAssertEqual(exportedThreads[2].stack, expectedOtherThreadStack) } + func testWhenLastFrameInThreadStackHasNoLibraryBaseAddress_itIsNotFilteredOut() { + let crashedThreadStackFrames: [StackFrame] = [ + .init(number: 0, libraryName: "Foo", libraryBaseAddress: 100, instructionPointer: 102), + .init(number: 1, libraryName: "Foo", libraryBaseAddress: 100, instructionPointer: 112), + .init(number: 2, libraryName: "Bizz", libraryBaseAddress: 400, instructionPointer: 432), + .init(number: 3, libraryName: nil, libraryBaseAddress: nil, instructionPointer: 432), + ] + + crashReport.threads = [ + .init(threadNumber: 0, crashed: true, stackFrames: crashedThreadStackFrames), + ] + + let actualStack = exporter.export(crashReport).threads[0].stack + let expectedStack = """ + 0 Foo 0x0000000000000066 0x64 + 2 + 1 Foo 0x0000000000000070 0x64 + 12 + 2 Bizz 0x00000000000001b0 0x190 + 32 + 3 ??? 0x00000000000001b0 0x0 + 0 + """ + + XCTAssertEqual(actualStack, expectedStack) + } + // MARK: - Formatting binary images func testExportingBinaryImages() { From 5e7e5ed5303604c1d6981cc1325e6c339a00dd99 Mon Sep 17 00:00:00 2001 From: Maciek Grzybowski Date: Tue, 29 Mar 2022 15:58:01 +0200 Subject: [PATCH 2/2] RUMM-2025 Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8752fd9e0..9b5f53b083 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * [FEATURE] Add tvOS Support. See [#793][] * [BUGFIX] Strip query parameters from span resource. See [#728][] * [BUGFIX] Stop reporting pre-warmed application launch time. See [#789][] +* [IMPROVEMENT] Crash Reporting: Filter out unrecognized trailing `???` stack frame in `error.stack`. See [#794][] # 1.9.0 / 01-26-2022 @@ -328,6 +329,7 @@ [#729]: https://github.com/DataDog/dd-sdk-ios/issues/729 [#789]: https://github.com/DataDog/dd-sdk-ios/issues/789 [#793]: https://github.com/DataDog/dd-sdk-ios/issues/793 +[#794]: https://github.com/DataDog/dd-sdk-ios/issues/794 [@00FA9A]: https://github.com/00FA9A [@Britton-Earnin]: https://github.com/Britton-Earnin [@Hengyu]: https://github.com/Hengyu