Files
sdk/pkg/vm_service/test/get_stack_test.dart
T
Clement Skau f2dfe3a8be [vm/debugger] Fixes async CollectAwaiterReturn()
The async, off-stack part of DebuggerStackTrace::CollectAwaiterReturn's
stack unwinding incorrectly looked on the stack instead of following
the Closure's awaiter chain.
This caused the async stack traces to be truncated and missing any
async frames, in turn causing ShouldPauseOnException to incorrectly
conclude no handler frame existing.
This would affect any case where the exception handling was located
around any except for the inner most awaiter.

TEST=Added regression test to pause_on_unhandled_exceptions_catcherror_test

Closes: https://github.com/dart-lang/sdk/issues/37953
Bug: https://github.com/dart-lang/sdk/issues/37953
Change-Id: I34a2b5ce3c7532032b2ef3dfbc2af7294d13a4c7
Cq-Do-Not-Cancel-Tryjobs: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/187405
Commit-Queue: Clement Skau <cskau@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
2021-02-26 06:46:36 +00:00

164 lines
5.9 KiB
Dart

// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--lazy-async-stacks --verbose_debug
import 'dart:developer';
import 'package:vm_service/vm_service.dart';
import 'package:test/test.dart';
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
const LINE_A = 33;
const LINE_B = 35;
Future<void> testMain() async {
await func1();
}
Future func1() async => await func2();
Future func2() async => await func3();
Future func3() async => await func4();
Future func4() async => await func5();
Future func5() async => await func6();
Future func6() async => await func7();
Future func7() async => await func8();
Future func8() async => await func9();
Future func9() async => await func10();
Future func10() async {
debugger(); // LINE_A
await 0;
debugger(); // LINE_B
print("Hello, world!");
}
void expectFrame(
final frame, final kindExpectation, final codeNameExpectation) {
expect(frame.kind, kindExpectation);
expect(frame.code?.name, codeNameExpectation);
}
void expectFrames(final frames, final expectKindAndCodeName) {
for (int i = 0; i < expectKindAndCodeName.length; i++) {
expectFrame(
frames[i], expectKindAndCodeName[i][0], expectKindAndCodeName[i][1]);
}
}
final tests = <IsolateTest>[
// Before the first await.
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_A),
// At LINE_A we're still running sync. so no asyncCausalFrames.
(VmService service, IsolateRef isolateRef) async {
final result = await service.getStack(isolateRef.id!);
expect(result.frames, hasLength(16));
expect(result.asyncCausalFrames, isNull);
expect(result.awaiterFrames, hasLength(16));
expectFrames(result.frames, [
[equals('Regular'), endsWith(' func10')],
[equals('Regular'), endsWith(' func9')],
[equals('Regular'), endsWith(' func8')],
[equals('Regular'), endsWith(' func7')],
[equals('Regular'), endsWith(' func6')],
[equals('Regular'), endsWith(' func5')],
[equals('Regular'), endsWith(' func4')],
[equals('Regular'), endsWith(' func3')],
[equals('Regular'), endsWith(' func2')],
[equals('Regular'), endsWith(' func1')],
[equals('Regular'), endsWith(' testMain')],
]);
expectFrames(result.awaiterFrames, [
[equals('AsyncActivation'), endsWith(' func10')],
[equals('AsyncActivation'), endsWith(' func9')],
[equals('AsyncActivation'), endsWith(' func8')],
[equals('AsyncActivation'), endsWith(' func7')],
[equals('AsyncActivation'), endsWith(' func6')],
[equals('AsyncActivation'), endsWith(' func5')],
[equals('AsyncActivation'), endsWith(' func4')],
[equals('AsyncActivation'), endsWith(' func3')],
[equals('AsyncActivation'), endsWith(' func2')],
[equals('AsyncActivation'), endsWith(' func1')],
[equals('AsyncActivation'), endsWith(' testMain')],
]);
},
resumeIsolate,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_B),
// After resuming the continuation - i.e. running async.
(VmService service, IsolateRef isolateRef) async {
final result = await service.getStack(isolateRef.id!);
expect(result.frames, hasLength(10));
expect(result.asyncCausalFrames, hasLength(26));
expect(result.awaiterFrames, hasLength(13));
expectFrames(result.frames!, [
[equals('Regular'), endsWith(' func10')],
[equals('Regular'), endsWith(' _RootZone.runUnary')],
[equals('Regular'), anything], // Internal mech. ..
[equals('Regular'), anything],
[equals('Regular'), anything],
[equals('Regular'), anything],
[equals('Regular'), anything],
[equals('Regular'), anything],
[equals('Regular'), anything],
[equals('Regular'), endsWith(' _RawReceivePortImpl._handleMessage')],
]);
expectFrames(result.asyncCausalFrames, [
[equals('Regular'), endsWith(' func10')],
[equals('AsyncSuspensionMarker'), isNull],
[equals('AsyncCausal'), endsWith(' func9')],
[equals('AsyncSuspensionMarker'), isNull],
[equals('AsyncCausal'), endsWith(' func8')],
[equals('AsyncSuspensionMarker'), isNull],
[equals('AsyncCausal'), endsWith(' func7')],
[equals('AsyncSuspensionMarker'), isNull],
[equals('AsyncCausal'), endsWith(' func6')],
[equals('AsyncSuspensionMarker'), isNull],
[equals('AsyncCausal'), endsWith(' func5')],
[equals('AsyncSuspensionMarker'), isNull],
[equals('AsyncCausal'), endsWith(' func4')],
[equals('AsyncSuspensionMarker'), isNull],
[equals('AsyncCausal'), endsWith(' func3')],
[equals('AsyncSuspensionMarker'), isNull],
[equals('AsyncCausal'), endsWith(' func2')],
[equals('AsyncSuspensionMarker'), isNull],
[equals('AsyncCausal'), endsWith(' func1')],
[equals('AsyncSuspensionMarker'), isNull],
[equals('AsyncCausal'), endsWith(' testMain')],
[equals('AsyncSuspensionMarker'), isNull],
]);
expectFrames(result.awaiterFrames, [
[equals('AsyncActivation'), endsWith(' func10')],
[equals('AsyncActivation'), endsWith(' func9')],
[equals('AsyncActivation'), endsWith(' func8')],
[equals('AsyncActivation'), endsWith(' func7')],
[equals('AsyncActivation'), endsWith(' func6')],
[equals('AsyncActivation'), endsWith(' func5')],
[equals('AsyncActivation'), endsWith(' func4')],
[equals('AsyncActivation'), endsWith(' func3')],
[equals('AsyncActivation'), endsWith(' func2')],
[equals('AsyncActivation'), endsWith(' func1')],
[equals('AsyncActivation'), endsWith(' testMain')],
[equals('AsyncActivation'), endsWith(' _ServiceTesteeRunner.run')],
[equals('AsyncActivation'), endsWith(' runIsolateTests')],
]);
},
];
main([args = const <String>[]]) => runIsolateTests(
args,
tests,
'get_stack_test.dart',
testeeConcurrent: testMain,
);