Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Catch errors when calculating frames in the stack trace #2408

Merged
merged 6 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading