Skip to content

Commit b0494fb

Browse files
authored
Catch errors when calculating frames in the stack trace (#2408)
1 parent 3a10b76 commit b0494fb

File tree

4 files changed

+50
-30
lines changed

4 files changed

+50
-30
lines changed

dwds/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
- Do not persist breakpoints across hot restarts or page reloads. - [#2371](https://github.com/dart-lang/webdev/pull/2371)
55
- If `pause_isolates_on_start` is `true`, wait for `resume` to run the app's `main` method. - [#2378](https://github.com/dart-lang/webdev/pull/2378)
66
- Fix bug where setting breakpoints in a project using macros would fail. - [#2403](https://github.com/dart-lang/webdev/pull/2403)
7+
- Make stack trace calculation resilient against one frame throwing an error. - [#2408](https://github.com/dart-lang/webdev/pull/2408)
78

89
**Breaking changes**
910

dwds/lib/src/debugging/debugger.dart

+7-1
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,13 @@ class Debugger extends Domain {
462462

463463
// Don't populate variables for async frames.
464464
if (populateVariables) {
465-
dartFrame.vars = await variablesFor(frame);
465+
try {
466+
dartFrame.vars = await variablesFor(frame);
467+
} catch (e) {
468+
logger.warning(
469+
'Error calculating Dart variables for frame $frameIndex: $e',
470+
);
471+
}
466472
}
467473

468474
return dartFrame;

dwds/lib/src/debugging/frame_computer.dart

+40-28
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44

55
import 'package:dwds/src/debugging/debugger.dart';
66
import 'package:dwds/src/utilities/synchronized.dart';
7+
import 'package:logging/logging.dart';
78
import 'package:vm_service/vm_service.dart';
89
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';
910

1011
class FrameComputer {
12+
static final logger = Logger('FrameComputer');
13+
1114
final Debugger debugger;
1215

1316
// To ensure that the frames are computed only once, we use an atomic queue
@@ -58,12 +61,16 @@ class FrameComputer {
5861
Future<void> _collectSyncFrames({int? limit}) async {
5962
while (_frameIndex < _callFrames.length) {
6063
if (limit != null && _computedFrames.length == limit) return;
61-
62-
final callFrame = _callFrames[_frameIndex];
63-
final dartFrame =
64-
await debugger.calculateDartFrameFor(callFrame, _frameIndex++);
65-
if (dartFrame != null) {
66-
_computedFrames.add(dartFrame);
64+
try {
65+
final callFrame = _callFrames[_frameIndex];
66+
final dartFrame =
67+
await debugger.calculateDartFrameFor(callFrame, _frameIndex++);
68+
if (dartFrame != null) {
69+
_computedFrames.add(dartFrame);
70+
}
71+
} catch (e) {
72+
// If there is an error calculating the frame, then skip it.
73+
logger.warning('Error calculating sync frame: $e');
6774
}
6875
}
6976
}
@@ -93,28 +100,33 @@ class FrameComputer {
93100
final asyncFramesToProcess = _asyncFramesToProcess!;
94101
// Process a single async frame.
95102
if (asyncFramesToProcess.isNotEmpty) {
96-
final callFrame = asyncFramesToProcess.removeAt(0);
97-
final location = WipLocation.fromValues(
98-
callFrame.scriptId,
99-
callFrame.lineNumber,
100-
columnNumber: callFrame.columnNumber,
101-
);
102-
103-
final tempWipFrame = WipCallFrame({
104-
'url': callFrame.url,
105-
'functionName': callFrame.functionName,
106-
'location': location.json,
107-
'scopeChain': [],
108-
});
109-
110-
final frame = await debugger.calculateDartFrameFor(
111-
tempWipFrame,
112-
_frameIndex++,
113-
populateVariables: false,
114-
);
115-
if (frame != null) {
116-
frame.kind = FrameKind.kAsyncCausal;
117-
_computedFrames.add(frame);
103+
try {
104+
final callFrame = asyncFramesToProcess.removeAt(0);
105+
final location = WipLocation.fromValues(
106+
callFrame.scriptId,
107+
callFrame.lineNumber,
108+
columnNumber: callFrame.columnNumber,
109+
);
110+
111+
final tempWipFrame = WipCallFrame({
112+
'url': callFrame.url,
113+
'functionName': callFrame.functionName,
114+
'location': location.json,
115+
'scopeChain': [],
116+
});
117+
118+
final frame = await debugger.calculateDartFrameFor(
119+
tempWipFrame,
120+
_frameIndex++,
121+
populateVariables: false,
122+
);
123+
if (frame != null) {
124+
frame.kind = FrameKind.kAsyncCausal;
125+
_computedFrames.add(frame);
126+
}
127+
} catch (e) {
128+
// If there is an error calculating the frame, then skip it.
129+
logger.warning('Error calculating async frame: $e');
118130
}
119131
}
120132
}

dwds/test/debugger_test.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ void main() async {
204204
Debugger.logger.onRecord,
205205
emitsThrough(
206206
predicate(
207-
(LogRecord log) => log.message == 'Error calculating Dart frames',
207+
(LogRecord log) =>
208+
log.message.contains('Error calculating sync frame'),
208209
),
209210
),
210211
);

0 commit comments

Comments
 (0)