Skip to content

Commit 96b83bd

Browse files
nateboschClement Skau
and
Clement Skau
authored
Async gap fixes (flutter#96)
* Fix async gap handling. (backpublish) Fix an issue where an async gap at the end of a stack trace would not get parsed correctly due to the trailing newline being `trim()`'d. Add tests to cover this case. * Fixes async gap handling in Trace.parse and Chain.parse (backpublish) Co-authored-by: Clement Skau <[email protected]>
1 parent 56811db commit 96b83bd

File tree

7 files changed

+80
-6
lines changed

7 files changed

+80
-6
lines changed

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## 1.9.6 (backpublish)
2+
3+
* Fix bug parsing asynchronous suspension gap markers at the end of stack
4+
traces. (Also fixed separately in 1.10.0-nullsafety.3)
5+
* Fix bug parsing asynchronous suspension gap markers at the end of stack
6+
traces, when parsing with `Trace.parse` and `Chain.parse`. (Also fixed
7+
separately in 1.10.0-nullsafety.6)
8+
19
## 1.9.5
210

311
* Parse the format for `data:` URIs that the Dart VM has used since `2.2.0`.

lib/src/chain.dart

+4-2
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,10 @@ class Chain implements StackTrace {
173173
factory Chain.parse(String chain) {
174174
if (chain.isEmpty) return Chain([]);
175175
if (chain.contains(vmChainGap)) {
176-
return Chain(
177-
chain.split(vmChainGap).map((trace) => Trace.parseVM(trace)));
176+
return Chain(chain
177+
.split(vmChainGap)
178+
.where((line) => line.isNotEmpty)
179+
.map((trace) => Trace.parseVM(trace)));
178180
}
179181
if (!chain.contains(chainGap)) return Chain([Trace.parse(chain)]);
180182

lib/src/trace.dart

+10-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,16 @@ class Trace implements StackTrace {
153153
static List<Frame> _parseVM(String trace) {
154154
// Ignore [vmChainGap]. This matches the behavior of
155155
// `Chain.parse().toTrace()`.
156-
var lines = trace.trim().replaceAll(vmChainGap, '').split('\n');
156+
var lines = trace
157+
.trim()
158+
.replaceAll(vmChainGap, '')
159+
.split('\n')
160+
.where((line) => line.isNotEmpty);
161+
162+
if (lines.isEmpty) {
163+
return [];
164+
}
165+
157166
var frames = lines
158167
.take(lines.length - 1)
159168
.map((line) => Frame.parseVM(line))

lib/src/utils.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const chainGap = '===== asynchronous gap ===========================\n';
88

99
/// The line used in the string representation of VM stack chains to represent
1010
/// the gap between traces.
11-
const vmChainGap = '<asynchronous suspension>\n';
11+
final vmChainGap = RegExp(r'^<asynchronous suspension>\n?$', multiLine: true);
1212

1313
// TODO(nweiz): When cross-platform imports work, use them to set this.
1414
/// Whether we're running in a JS context.

pubspec.yaml

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
name: stack_trace
2-
version: 1.9.5
3-
2+
version: 1.9.6
43
description: A package for manipulating stack traces and printing them readably.
54
homepage: https://github.com/dart-lang/stack_trace
65

test/chain/chain_test.dart

+15
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,21 @@ void main() {
3636
expect(chain.traces[1].frames, isEmpty);
3737
expect(chain.traces[2].frames, isEmpty);
3838
});
39+
40+
test('parses a chain with VM gaps', () {
41+
final chain =
42+
Chain.parse('#1 MyClass.run (package:my_lib.dart:134:5)\n'
43+
'<asynchronous suspension>\n'
44+
'#2 main (file:///my_app.dart:9:3)\n'
45+
'<asynchronous suspension>\n');
46+
expect(chain.traces, hasLength(2));
47+
expect(chain.traces[0].frames, hasLength(1));
48+
expect(chain.traces[0].frames[0].toString(),
49+
equals('package:my_lib.dart 134:5 in MyClass.run'));
50+
expect(chain.traces[1].frames, hasLength(1));
51+
expect(chain.traces[1].frames[0].toString(),
52+
equals('/my_app.dart 9:3 in main'));
53+
});
3954
});
4055

4156
group('Chain.capture()', () {

test/trace_test.dart

+41
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,25 @@ void main() {
249249
equals(Uri.parse('https://dart.dev/foo/quux.dart')));
250250
});
251251

252+
test('parses a package:stack_trace stack chain with end gap correctly', () {
253+
var trace =
254+
Trace.parse('https://dart.dev/foo/bar.dart 10:11 Foo.<fn>.bar\n'
255+
'https://dart.dev/foo/baz.dart Foo.<fn>.bar\n'
256+
'https://dart.dev/foo/bang.dart 10:11 Foo.<fn>.bar\n'
257+
'https://dart.dev/foo/quux.dart Foo.<fn>.bar'
258+
'===== asynchronous gap ===========================\n');
259+
260+
expect(trace.frames.length, 4);
261+
expect(trace.frames[0].uri,
262+
equals(Uri.parse('https://dart.dev/foo/bar.dart')));
263+
expect(trace.frames[1].uri,
264+
equals(Uri.parse('https://dart.dev/foo/baz.dart')));
265+
expect(trace.frames[2].uri,
266+
equals(Uri.parse('https://dart.dev/foo/bang.dart')));
267+
expect(trace.frames[3].uri,
268+
equals(Uri.parse('https://dart.dev/foo/quux.dart')));
269+
});
270+
252271
test('parses a real package:stack_trace stack trace correctly', () {
253272
var traceString = Trace.current().toString();
254273
expect(Trace.parse(traceString).toString(), equals(traceString));
@@ -259,6 +278,28 @@ void main() {
259278
expect(trace.frames, isEmpty);
260279
expect(trace.toString(), equals(''));
261280
});
281+
282+
test('parses trace with async gap correctly', () {
283+
var trace = Trace.parse('#0 bop (file:///pull.dart:42:23)\n'
284+
'<asynchronous suspension>\n'
285+
'#1 twist (dart:the/future.dart:0:2)\n'
286+
'#2 main (dart:my/file.dart:4:6)\n');
287+
288+
expect(trace.frames.length, 3);
289+
expect(trace.frames[0].uri, equals(Uri.parse('file:///pull.dart')));
290+
expect(trace.frames[1].uri, equals(Uri.parse('dart:the/future.dart')));
291+
expect(trace.frames[2].uri, equals(Uri.parse('dart:my/file.dart')));
292+
});
293+
294+
test('parses trace with async gap at end correctly', () {
295+
var trace = Trace.parse('#0 bop (file:///pull.dart:42:23)\n'
296+
'#1 twist (dart:the/future.dart:0:2)\n'
297+
'<asynchronous suspension>\n');
298+
299+
expect(trace.frames.length, 2);
300+
expect(trace.frames[0].uri, equals(Uri.parse('file:///pull.dart')));
301+
expect(trace.frames[1].uri, equals(Uri.parse('dart:the/future.dart')));
302+
});
262303
});
263304

264305
test('.toString() nicely formats the stack trace', () {

0 commit comments

Comments
 (0)