[vm/debugger] Fix notify-debugger-.. for yielding.

For yielding functions (async, sync*, async*) we need to look for
annotations on the outer function instead of the synthetic inner
function associated with the handler frame.

Fixes https://github.com/dart-lang/sdk/issues/45673

TEST=runtime/observatory{,_2}/tests/service{,_2}/notify_debugger_on_exception_yielding_test.dart

Bug: https://github.com/dart-lang/sdk/issues/45673
Change-Id: I8b1718b3614852f6f8db98811177b21fe587fea1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/198408
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Commit-Queue: Clement Skau <cskau@google.com>
This commit is contained in:
Clement Skau
2021-05-06 17:59:33 +00:00
committed by commit-bot@chromium.org
parent f53af0d445
commit 69ebb404e7
3 changed files with 145 additions and 1 deletions
@@ -0,0 +1,64 @@
// Copyright (c) 2021, 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=--verbose_debug
// See: https://github.com/dart-lang/sdk/issues/45673
import 'test_helper.dart';
import 'service_test_common.dart';
const int LINE_A = 19;
const int LINE_B = 29;
const int LINE_C = 39;
@pragma('vm:notify-debugger-on-exception')
Future<void> throwFromAsync() async {
try {
throw 'Throw from throwFromAsync'; // LINE_A
} catch (e) {
// Ignore. Internals will notify debugger.
}
return Future.value();
}
@pragma('vm:notify-debugger-on-exception')
Stream<int> throwFromAsyncStar() async* {
try {
throw 'Throw from throwFromAsyncStar'; // LINE_B
} catch (e) {
// Ignore. Internals will notify debugger.
}
yield 13;
}
@pragma('vm:notify-debugger-on-exception')
Iterable<int> throwFromSyncStar() sync* {
try {
throw 'Throw from throwFromSyncStar'; // LINE_C
} catch (e) {
// Ignore. Internals will notify debugger.
}
yield 7;
}
testMain() async {
throwFromAsync();
await for (var e in throwFromAsyncStar()) {/*ignore*/}
for (var e in throwFromSyncStar()) {/*ignore*/}
}
final tests = <IsolateTest>[
hasStoppedWithUnhandledException,
stoppedAtLine(LINE_A),
resumeIsolate,
hasStoppedWithUnhandledException,
stoppedAtLine(LINE_B),
resumeIsolate,
hasStoppedWithUnhandledException,
stoppedAtLine(LINE_C),
];
main([args = const <String>[]]) => runIsolateTests(args, tests,
testeeConcurrent: testMain, pause_on_unhandled_exceptions: true);
@@ -0,0 +1,64 @@
// Copyright (c) 2021, 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=--verbose_debug
// See: https://github.com/dart-lang/sdk/issues/45673
import 'test_helper.dart';
import 'service_test_common.dart';
const int LINE_A = 19;
const int LINE_B = 29;
const int LINE_C = 39;
@pragma('vm:notify-debugger-on-exception')
Future<void> throwFromAsync() async {
try {
throw 'Throw from throwFromAsync'; // LINE_A
} catch (e) {
// Ignore. Internals will notify debugger.
}
return Future.value();
}
@pragma('vm:notify-debugger-on-exception')
Stream<int> throwFromAsyncStar() async* {
try {
throw 'Throw from throwFromAsyncStar'; // LINE_B
} catch (e) {
// Ignore. Internals will notify debugger.
}
yield 13;
}
@pragma('vm:notify-debugger-on-exception')
Iterable<int> throwFromSyncStar() sync* {
try {
throw 'Throw from throwFromSyncStar'; // LINE_C
} catch (e) {
// Ignore. Internals will notify debugger.
}
yield 7;
}
testMain() async {
throwFromAsync();
await for (var e in throwFromAsyncStar()) {/*ignore*/}
for (var e in throwFromSyncStar()) {/*ignore*/}
}
final tests = <IsolateTest>[
hasStoppedWithUnhandledException,
stoppedAtLine(LINE_A),
resumeIsolate,
hasStoppedWithUnhandledException,
stoppedAtLine(LINE_B),
resumeIsolate,
hasStoppedWithUnhandledException,
stoppedAtLine(LINE_C),
];
main([args = const <String>[]]) => runIsolateTests(args, tests,
testeeConcurrent: testMain, pause_on_unhandled_exceptions: true);
+17 -1
View File
@@ -2248,11 +2248,27 @@ bool Debugger::ShouldPauseOnException(DebuggerStackTrace* stack_trace,
// it will be caught once we unwind the stack.
return true;
}
auto& handler_function = Function::Handle(handler_frame->function().ptr());
// If the handler function is an synthetic inner function, we need to look for
// the annotations on the outer function.
if (handler_function.IsAsyncClosure()) {
// async :async_op
handler_function = handler_function.parent_function();
} else if (handler_frame->function().IsAsyncGenClosure()) {
// async* :async_op
handler_function = handler_function.parent_function();
} else if (handler_frame->function().IsSyncGenClosure()) {
// sync* :sync_op + :sync_op_gen
handler_function = handler_function.parent_function();
handler_function = handler_function.parent_function();
}
// If handler_frame's function is annotated with
// @pragma('vm:notify-debugger-on-exception'), we specifically want to notify
// the debugger of this otherwise ignored exception.
if (Library::FindPragma(Thread::Current(), /*only_core=*/false,
handler_frame->function(),
handler_function,
Symbols::vm_notify_debugger_on_exception())) {
return true;
}