diff --git a/pkg/native_stack_traces/CHANGELOG.md b/pkg/native_stack_traces/CHANGELOG.md index 38b806bcaf4..2d4d9d9a1b8 100644 --- a/pkg/native_stack_traces/CHANGELOG.md +++ b/pkg/native_stack_traces/CHANGELOG.md @@ -1,3 +1,11 @@ +## 0.5.5 + +- Fixed issue introduced by 0.5.4. + +## 0.5.4 + +- Relaxed requirement for spaces before non-symbolic stack trace line. + ## 0.5.3 - Exported more ELF utilities for use in Dart tests. diff --git a/pkg/native_stack_traces/lib/src/convert.dart b/pkg/native_stack_traces/lib/src/convert.dart index de255d01955..50ef580d7cb 100644 --- a/pkg/native_stack_traces/lib/src/convert.dart +++ b/pkg/native_stack_traces/lib/src/convert.dart @@ -125,9 +125,9 @@ const _symbolOffsetREString = r'(?' + constants.isolateSymbolName + r')\+(?(?:0x)?[\da-f]+)'; final _symbolOffsetRE = RegExp(_symbolOffsetREString); -final _traceLineRE = RegExp( - r' #(\d+) abs (?[\da-f]+)(?: virt (?[\da-f]+))? ' - r'(?.*)$'); +final _traceLineRE = + RegExp(r'\s*#(\d+) abs (?[\da-f]+)(?: virt (?[\da-f]+))?' + r' (?.*)$'); /// Parses strings of the format +, where /// is one of the static symbols used for Dart instruction @@ -272,8 +272,15 @@ class DwarfStackTraceDecoder extends StreamTransformerBase { // No lines to output (as this corresponds to Dart internals). if (callInfo.isEmpty) continue; // Output the lines for the symbolic frame with the prefix found on the - // original non-symbolic frame line. - final prefix = line.substring(0, lineMatch!.start); + // original non-symbolic frame line, modulo all whitespace between the + // prefix and stack trace information converted to a single space. + // + // If there was no prefix, just swallow any initial whitespace, since + // symbolic Dart stacktrace lines have no initial whitespace. + String prefix = line.substring(0, lineMatch!.start); + if (prefix.isNotEmpty) { + prefix += ' '; + } for (final call in callInfo) { yield prefix + _stackTracePiece(call, depth++); } diff --git a/pkg/native_stack_traces/pubspec.yaml b/pkg/native_stack_traces/pubspec.yaml index 39174a6e522..6af398d8e92 100644 --- a/pkg/native_stack_traces/pubspec.yaml +++ b/pkg/native_stack_traces/pubspec.yaml @@ -1,5 +1,5 @@ name: native_stack_traces -version: 0.5.3 +version: 0.5.5 description: Utilities for working with non-symbolic stack traces. repository: https://github.com/dart-lang/sdk/tree/main/pkg/native_stack_traces @@ -19,3 +19,4 @@ dependencies: # See also https://dart.dev/tools/pub/dependencies. dev_dependencies: lints: any + test: any diff --git a/pkg/native_stack_traces/test/convert/regress_262474517_test.dart b/pkg/native_stack_traces/test/convert/regress_262474517_test.dart new file mode 100644 index 00000000000..8a3f2eed1fb --- /dev/null +++ b/pkg/native_stack_traces/test/convert/regress_262474517_test.dart @@ -0,0 +1,39 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; + +import 'package:native_stack_traces/src/convert.dart'; +import 'package:native_stack_traces/src/dwarf.dart'; +import 'package:path/path.dart' as path; +import 'package:test/test.dart'; + +void main() { + group('convert tests', defineConvertTests); +} + +final String pkgDir = Platform.script.resolve('../..').toFilePath(); + +void defineConvertTests() { + test('b/262474517 regression', () async { + final inputDir = path.join(pkgDir, 'testcases', 'convert'); + // Test with a prefix without four spaces between prefix and trace. + testPath(path.join(inputDir, 'regress_262474517_trace.txt')); + // Test for no prefix or whitespace at all. + testPath(path.join(inputDir, 'regress_262474517_trace_2.txt')); + }); +} + +void testPath(String inputPath) async { + final contents = await File(inputPath).readAsLines(); + final pcOffsets = collectPCOffsets(contents); + expect(pcOffsets.map((o) => o.offset).toList(), + [0x14e87f, 0x2a4e27, 0x4ee12b, 0x477fc7]); + expect(pcOffsets.map((o) => o.section).toList(), [ + InstructionsSection.isolate, + InstructionsSection.isolate, + InstructionsSection.isolate, + InstructionsSection.isolate + ]); +} diff --git a/pkg/native_stack_traces/testcases/convert/regress_262474517_trace.txt b/pkg/native_stack_traces/testcases/convert/regress_262474517_trace.txt new file mode 100644 index 00000000000..15cfbed2b35 --- /dev/null +++ b/pkg/native_stack_traces/testcases/convert/regress_262474517_trace.txt @@ -0,0 +1,6 @@ +Non-fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: Bad state: No element. Error thrown null. +BuildId: c3126a4381294e13185549e5e94a4db9 +at . #00 abs 0 virt 000000000031ba6f _kDartIsolateSnapshotInstructions+0x14e87f +at . #01 abs 0 virt 0000000000472017 _kDartIsolateSnapshotInstructions+0x2a4e27 +at . #02 abs 0 virt 00000000006bb31b _kDartIsolateSnapshotInstructions+0x4ee12b +at . #03 abs 0 virt 00000000006451b7 _kDartIsolateSnapshotInstructions+0x477fc7 diff --git a/pkg/native_stack_traces/testcases/convert/regress_262474517_trace_2.txt b/pkg/native_stack_traces/testcases/convert/regress_262474517_trace_2.txt new file mode 100644 index 00000000000..f1287a3d2ac --- /dev/null +++ b/pkg/native_stack_traces/testcases/convert/regress_262474517_trace_2.txt @@ -0,0 +1,6 @@ +Non-fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: Bad state: No element. Error thrown null. +BuildId: c3126a4381294e13185549e5e94a4db9 +#00 abs 0 virt 000000000031ba6f _kDartIsolateSnapshotInstructions+0x14e87f +#01 abs 0 virt 0000000000472017 _kDartIsolateSnapshotInstructions+0x2a4e27 +#02 abs 0 virt 00000000006bb31b _kDartIsolateSnapshotInstructions+0x4ee12b +#03 abs 0 virt 00000000006451b7 _kDartIsolateSnapshotInstructions+0x477fc7