Skip to content

Commit

Permalink
Add support for Firefox anonymous stackTraces (flutter#55)
Browse files Browse the repository at this point in the history
Co-authored-by: Sinegovsky Ivan <ivan.sinegovsky@team.wrike.com>
  • Loading branch information
sinegovsky-ivan and sinegovsky-ivan authored Apr 11, 2020
1 parent 430d02f commit a337e89
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 1.9.4-dev

* Added support for firefox anonymous stack traces

## 1.9.3

* Set max SDK version to `<3.0.0`.
Expand Down
27 changes: 27 additions & 0 deletions lib/src/frame.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ final _v8UrlLocation = new RegExp(r'^(.*):(\d+):(\d+)|native$');
final _v8EvalLocation =
new RegExp(r'^eval at (?:\S.*?) \((.*)\)(?:, .*?:\d+:\d+)?$');

// anonymous/<@http://pub.dartlang.org/stuff.js line 693 > Function:3:40
// anonymous/<@http://pub.dartlang.org/stuff.js line 693 > eval:3:40
final _firefoxEvalLocation =
new RegExp(r"(\S+)@(\S+) line (\d+) >.* (Function|eval):\d+:\d+");

// .VW.call$0@http://pub.dartlang.org/stuff.dart.js:560
// .VW.call$0("arg")@http://pub.dartlang.org/stuff.dart.js:560
// .VW.call$0/name<@http://pub.dartlang.org/stuff.dart.js:560
Expand Down Expand Up @@ -205,11 +210,33 @@ class Frame {
/// be retrieved.
factory Frame.parseIE(String frame) => new Frame.parseV8(frame);

/// Parses a string representation of a Firefox 'eval' or 'function' stack frame.
///
/// for example:
/// anonymous/<@http://pub.dartlang.org/stuff.js line 693 > Function:3:40
/// anonymous/<@http://pub.dartlang.org/stuff.js line 693 > eval:3:40
factory Frame._parseFirefoxEval(String frame) =>
_catchFormatException(frame, () {
final match = _firefoxEvalLocation.firstMatch(frame);
if (match == null) return new UnparsedFrame(frame);
var member = match[1].replaceAll('/<', '');
final uri = _uriOrPathToUri(match[2]);
final line = int.parse(match[3]);
if (member.isEmpty || member == 'anonymous') {
member = '<fn>';
}
return new Frame(uri, line, null, member);
});

/// Parses a string representation of a Firefox stack frame.
factory Frame.parseFirefox(String frame) => _catchFormatException(frame, () {
var match = _firefoxSafariFrame.firstMatch(frame);
if (match == null) return new UnparsedFrame(frame);

if (match[3].contains(' line ')) {
return Frame._parseFirefoxEval(frame);
}

// Normally this is a URI, but in a jsshell trace it can be a path.
var uri = _uriOrPathToUri(match[3]);

Expand Down
11 changes: 10 additions & 1 deletion lib/src/trace.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ final _v8Trace = new RegExp(r"\n ?at ");
/// though it is possible for the message to match this as well.
final _v8TraceLine = new RegExp(r" ?at ");

/// A RegExp to match Firefox's eval and Function stack traces.
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stack
/// These stack traces looks like:
/// anonymous/<@http://pub.dartlang.org/stuff.js line 693 > Function:3:40
/// anonymous/<@http://pub.dartlang.org/stuff.js line 693 > eval:3:40
final _firefoxEvalTrace =
new RegExp(r"@\S+ line \d+ >.* (Function|eval):\d+:\d+");

/// A RegExp to match Firefox and Safari's stack traces.
///
/// Firefox and Safari have very similar stack trace formats, so we use the same
Expand Down Expand Up @@ -120,7 +128,8 @@ class Trace implements StackTrace {
if (trace.isEmpty) return new Trace(<Frame>[]);
if (trace.contains(_v8Trace)) return new Trace.parseV8(trace);
if (trace.contains("\tat ")) return new Trace.parseJSCore(trace);
if (trace.contains(_firefoxSafariTrace)) {
if (trace.contains(_firefoxSafariTrace) ||
trace.contains(_firefoxEvalTrace)) {
return new Trace.parseFirefox(trace);
}
if (trace.contains(chainGap)) return new Chain.parse(trace).toTrace();
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ name: stack_trace
#
# When the major version is upgraded, you *must* update that version constraint
# in pub to stay in sync with this.
version: 1.9.3
version: 1.9.4-dev

description: A package for manipulating stack traces and printing them readably.
author: 'Dart Team <misc@dartlang.org>'
Expand Down
46 changes: 46 additions & 0 deletions test/frame_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,52 @@ void main() {
});

group('.parseFirefox/.parseSafari', () {
test('parses a Firefox stack trace with anonymous function', () {
var trace = new Trace.parse('''
Foo._bar@http://pub.dartlang.org/stuff.js:18056:12
anonymous/<@http://pub.dartlang.org/stuff.js line 693 > Function:3:40
baz@http://pub.dartlang.org/buz.js:56355:55
''');
expect(trace.frames[0].uri,
equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
expect(trace.frames[0].line, equals(18056));
expect(trace.frames[0].column, equals(12));
expect(trace.frames[0].member, equals("Foo._bar"));
expect(trace.frames[1].uri,
equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
expect(trace.frames[1].line, equals(693));
expect(trace.frames[1].column, isNull);
expect(trace.frames[1].member, equals("<fn>"));
expect(trace.frames[2].uri,
equals(Uri.parse("http://pub.dartlang.org/buz.js")));
expect(trace.frames[2].line, equals(56355));
expect(trace.frames[2].column, equals(55));
expect(trace.frames[2].member, equals("baz"));
});

test(
'parses a Firefox stack trace with nested evals in anonymous function correctly',
() {
var trace = new Trace.parse('''
Foo._bar@http://pub.dartlang.org/stuff.js:18056:12
anonymous@file:///C:/example.html line 7 > eval line 1 > eval:1:1
anonymous@file:///C:/example.html line 45 > Function:1:1
''');
expect(trace.frames[0].uri,
equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
expect(trace.frames[0].line, equals(18056));
expect(trace.frames[0].column, equals(12));
expect(trace.frames[0].member, equals("Foo._bar"));
expect(trace.frames[1].uri, equals(Uri.parse("file:///C:/example.html")));
expect(trace.frames[1].line, equals(7));
expect(trace.frames[1].column, isNull);
expect(trace.frames[1].member, equals("<fn>"));
expect(trace.frames[2].uri, equals(Uri.parse("file:///C:/example.html")));
expect(trace.frames[2].line, equals(45));
expect(trace.frames[2].column, isNull);
expect(trace.frames[2].member, equals("<fn>"));
});

test('parses a simple stack frame correctly', () {
var frame = new Frame.parseFirefox(
".VW.call\$0@http://pub.dartlang.org/stuff.dart.js:560");
Expand Down

0 comments on commit a337e89

Please sign in to comment.