Skip to content

Commit

Permalink
Catch errors when calculating frames in the stack trace (#2408)
Browse files Browse the repository at this point in the history
  • Loading branch information
elliette authored Apr 18, 2024
1 parent 3a10b76 commit b0494fb
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 30 deletions.
1 change: 1 addition & 0 deletions dwds/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- Do not persist breakpoints across hot restarts or page reloads. - [#2371](https://github.com/dart-lang/webdev/pull/2371)
- 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)
- Fix bug where setting breakpoints in a project using macros would fail. - [#2403](https://github.com/dart-lang/webdev/pull/2403)
- Make stack trace calculation resilient against one frame throwing an error. - [#2408](https://github.com/dart-lang/webdev/pull/2408)

**Breaking changes**

Expand Down
8 changes: 7 additions & 1 deletion dwds/lib/src/debugging/debugger.dart
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,13 @@ class Debugger extends Domain {

// Don't populate variables for async frames.
if (populateVariables) {
dartFrame.vars = await variablesFor(frame);
try {
dartFrame.vars = await variablesFor(frame);
} catch (e) {
logger.warning(
'Error calculating Dart variables for frame $frameIndex: $e',
);
}
}

return dartFrame;
Expand Down
68 changes: 40 additions & 28 deletions dwds/lib/src/debugging/frame_computer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@

import 'package:dwds/src/debugging/debugger.dart';
import 'package:dwds/src/utilities/synchronized.dart';
import 'package:logging/logging.dart';
import 'package:vm_service/vm_service.dart';
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';

class FrameComputer {
static final logger = Logger('FrameComputer');

final Debugger debugger;

// To ensure that the frames are computed only once, we use an atomic queue
Expand Down Expand Up @@ -58,12 +61,16 @@ class FrameComputer {
Future<void> _collectSyncFrames({int? limit}) async {
while (_frameIndex < _callFrames.length) {
if (limit != null && _computedFrames.length == limit) return;

final callFrame = _callFrames[_frameIndex];
final dartFrame =
await debugger.calculateDartFrameFor(callFrame, _frameIndex++);
if (dartFrame != null) {
_computedFrames.add(dartFrame);
try {
final callFrame = _callFrames[_frameIndex];
final dartFrame =
await debugger.calculateDartFrameFor(callFrame, _frameIndex++);
if (dartFrame != null) {
_computedFrames.add(dartFrame);
}
} catch (e) {
// If there is an error calculating the frame, then skip it.
logger.warning('Error calculating sync frame: $e');
}
}
}
Expand Down Expand Up @@ -93,28 +100,33 @@ class FrameComputer {
final asyncFramesToProcess = _asyncFramesToProcess!;
// Process a single async frame.
if (asyncFramesToProcess.isNotEmpty) {
final callFrame = asyncFramesToProcess.removeAt(0);
final location = WipLocation.fromValues(
callFrame.scriptId,
callFrame.lineNumber,
columnNumber: callFrame.columnNumber,
);

final tempWipFrame = WipCallFrame({
'url': callFrame.url,
'functionName': callFrame.functionName,
'location': location.json,
'scopeChain': [],
});

final frame = await debugger.calculateDartFrameFor(
tempWipFrame,
_frameIndex++,
populateVariables: false,
);
if (frame != null) {
frame.kind = FrameKind.kAsyncCausal;
_computedFrames.add(frame);
try {
final callFrame = asyncFramesToProcess.removeAt(0);
final location = WipLocation.fromValues(
callFrame.scriptId,
callFrame.lineNumber,
columnNumber: callFrame.columnNumber,
);

final tempWipFrame = WipCallFrame({
'url': callFrame.url,
'functionName': callFrame.functionName,
'location': location.json,
'scopeChain': [],
});

final frame = await debugger.calculateDartFrameFor(
tempWipFrame,
_frameIndex++,
populateVariables: false,
);
if (frame != null) {
frame.kind = FrameKind.kAsyncCausal;
_computedFrames.add(frame);
}
} catch (e) {
// If there is an error calculating the frame, then skip it.
logger.warning('Error calculating async frame: $e');
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion dwds/test/debugger_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ void main() async {
Debugger.logger.onRecord,
emitsThrough(
predicate(
(LogRecord log) => log.message == 'Error calculating Dart frames',
(LogRecord log) =>
log.message.contains('Error calculating sync frame'),
),
),
);
Expand Down

0 comments on commit b0494fb

Please sign in to comment.