[vm] Rename tests causal_stacks -> awaiter_stacks and improve harness.

The main difference from the previous harness is that it
allows auto updating the expectations instead of
maintaining them manually.

This relands 0c1b2722ed with
changes to harness which fix issues on Windows.

Note: some amount of AOT failures are expected and should just
be approved. They will be fixed with the last CL in the series.

TEST=ci

Cq-Include-Trybots: luci.dart.try:vm-win-release-x64-try
Change-Id: I7ae84769ed54bc447ebf71acc68ba9d0b6717bac
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/311604
Reviewed-by: Tess Strickland <sstrickl@google.com>
Commit-Queue: Slava Egorov <vegorov@google.com>
Auto-Submit: Slava Egorov <vegorov@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
This commit is contained in:
Slava Egorov 2023-06-27 11:50:32 +00:00 committed by Commit Queue
parent 630482342f
commit 758727dd12
31 changed files with 2615 additions and 2409 deletions

View file

@ -2,7 +2,7 @@
// 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.
// This test is derived from `runtime/tests/vm/dart/causal_stacks/utils.dart`.
// This test is derived from `runtime/tests/vm/dart/awaiter_stacks/utils.dart`.
import 'dart:async';

View file

@ -5,7 +5,7 @@
"../vm/dart/byte_array_test.dart",
"../vm/dart/callee_side_type_checks_test.dart",
"../vm/dart/catch_entry_state_test.dart",
"../vm/dart/causal_stacks/sync_async_start_pkg_test_test.dart",
"../vm/dart/awaiter_stacks/sync_async_start_pkg_test_test.dart",
"../vm/dart/deferred_loading_and_weak_serialization_references_test.dart",
"../vm/dart/deferred_loading_call_modes_test.dart",
"../vm/dart/deopt/allocate_array_test.dart",
@ -3386,7 +3386,7 @@
"../vm/dart_2/byte_array_test.dart",
"../vm/dart_2/callee_side_type_checks_test.dart",
"../vm/dart_2/catch_entry_state_test.dart",
"../vm/dart_2/causal_stacks/sync_async_start_pkg_test_test.dart",
"../vm/dart_2/awaiter_stacks/sync_async_start_pkg_test_test.dart",
"../vm/dart_2/deferred_loading_and_weak_serialization_references_test.dart",
"../vm/dart_2/deferred_loading_call_modes_test.dart",
"../vm/dart_2/deopt/allocate_array_test.dart",

View file

@ -0,0 +1,712 @@
// Copyright (c) 2023, 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.
//
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
// make this test pass on vm-aot-dwarf-* builders.
//
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
import 'dart:async';
import 'package:expect/expect.dart';
import 'harness.dart' as harness;
// Test functions:
Future<void> throwSync() {
throw 'throw from throwSync';
}
Future<void> throwAsync() async {
await 0;
throw 'throw from throwAsync';
}
// ----
// Scenario: All async functions yielded at least once before throw:
// ----
Future<void> allYield() async {
await 0;
await allYield2();
}
Future<void> allYield2() async {
await 0;
await allYield3();
}
Future<void> allYield3() async {
await 0;
throwSync();
}
// ----
// Scenario: None of the async functions yielded before the throw:
// ----
Future<void> noYields() async {
await noYields2();
}
Future<void> noYields2() async {
await noYields3();
}
Future<void> noYields3() async {
throwSync();
}
// ----
// Scenario: Mixed yielding and non-yielding frames:
// ----
Future<void> mixedYields() async {
await mixedYields2();
}
Future<void> mixedYields2() async {
await 0;
await mixedYields3();
}
Future<void> mixedYields3() async {
return throwAsync();
}
// ----
// Scenario: Non-async frame:
// ----
Future<void> syncSuffix() async {
await syncSuffix2();
}
Future<void> syncSuffix2() async {
await 0;
await syncSuffix3();
}
Future<void> syncSuffix3() {
return throwAsync();
}
// ----
// Scenario: Caller is non-async, has no upwards stack:
// ----
Future nonAsyncNoStack() async => await nonAsyncNoStack1();
Future nonAsyncNoStack1() async => await nonAsyncNoStack2();
Future nonAsyncNoStack2() async => Future.value(0).then((_) => throwAsync());
// ----
// Scenario: async*:
// ----
Future awaitEveryAsyncStarThrowSync() async {
await for (Future v in asyncStarThrowSync()) {
await v;
}
}
Stream<Future> asyncStarThrowSync() async* {
for (int i = 0; i < 2; i++) {
await i;
yield throwSync();
}
}
Future awaitEveryAsyncStarThrowAsync() async {
await for (Future v in asyncStarThrowAsync()) {
await v;
}
}
Stream<Future> asyncStarThrowAsync() async* {
for (int i = 0; i < 2; i++) {
await i;
yield Future.value(i);
await throwAsync();
}
}
Future listenAsyncStarThrowAsync() async {
final _output = [];
// Listening to an async* doesn't create the usual await-for StreamIterator.
StreamSubscription ss = asyncStarThrowAsync().listen((Future f) {
_output.add('unique value');
});
await ss.asFuture();
if (_output.length == 44) {
print(_output);
}
}
// ----
// Scenario: All async functions yielded and we run in a custom zone with a
// custom error handler.
// ----
Future<void> customErrorZone() async {
final completer = Completer<void>();
runZonedGuarded(() async {
await allYield();
completer.complete(null);
}, (e, s) {
completer.completeError(e, s);
});
return completer.future;
}
// ----
// Scenario: Future.timeout:
// ----
Future awaitTimeout() async {
await (throwAsync().timeout(Duration(seconds: 1)));
}
// ----
// Scenario: Future.wait:
// ----
Future awaitWait() async {
await Future.wait([
throwAsync(),
() async {
await Future.value();
}()
]);
}
// ----
// Scenario: Future.whenComplete:
// ----
Future futureSyncWhenComplete() {
return Future.sync(throwAsync).whenComplete(() => 'nop');
}
// ----
// Scenario: Future.then:
// ----
Future futureThen() {
return Future.value(0).then((value) {
throwSync();
}).then(_doSomething);
}
void _doSomething(_) {
Expect.fail('Should not reach doSomething');
}
Future<void> doTestAwait(Future f()) async {
await f();
Expect.fail('No exception thrown!');
}
Future<void> doTestAwaitThen(Future f()) async {
// Passing (e) {} to then() can cause the closure instructions to be
// deduped, changing the stack trace to the deduped owner, so we
// duplicate the Expect.fail() call in the closure.
await f().then((e) => Expect.fail('No exception thrown!'));
}
Future<void> doTestAwaitCatchError(Future f()) async {
late Object error;
late StackTrace stackTrace;
await f().catchError((e, s) {
error = e;
stackTrace = s;
});
return Future.error(error, stackTrace);
}
Future<void> main(List<String> args) async {
if (harness.shouldSkip()) {
return;
}
harness.configure(currentExpectations);
final tests = [
allYield,
noYields,
mixedYields,
syncSuffix,
nonAsyncNoStack,
awaitEveryAsyncStarThrowSync,
awaitEveryAsyncStarThrowAsync,
listenAsyncStarThrowAsync,
customErrorZone,
awaitTimeout,
awaitWait,
futureSyncWhenComplete,
futureThen,
];
for (var test in tests) {
await harness.runTest(() => doTestAwait(test));
await harness.runTest(() => doTestAwaitThen(test));
await harness.runTest(() => doTestAwaitCatchError(test));
}
harness.updateExpectations();
}
// CURRENT EXPECTATIONS BEGIN
final currentExpectations = [
"""
#0 throwSync (%test%)
#1 allYield3 (%test%)
<asynchronous suspension>
#2 allYield2 (%test%)
<asynchronous suspension>
#3 allYield (%test%)
<asynchronous suspension>
#4 doTestAwait (%test%)
<asynchronous suspension>
#5 runTest (harness.dart)
<asynchronous suspension>
#6 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 allYield3 (%test%)
<asynchronous suspension>
#2 allYield2 (%test%)
<asynchronous suspension>
#3 allYield (%test%)
<asynchronous suspension>
#4 doTestAwaitThen (%test%)
<asynchronous suspension>
#5 runTest (harness.dart)
<asynchronous suspension>
#6 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 allYield3 (%test%)
<asynchronous suspension>
#2 allYield2 (%test%)
<asynchronous suspension>
#3 allYield (%test%)
<asynchronous suspension>
#4 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#5 runTest (harness.dart)
<asynchronous suspension>
#6 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 noYields3 (%test%)
#2 noYields2 (%test%)
#3 noYields (%test%)
#4 doTestAwait (%test%)
#5 main.<anonymous closure> (%test%)
#6 runTest (harness.dart)
#7 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 noYields3 (%test%)
#2 noYields2 (%test%)
#3 noYields (%test%)
#4 doTestAwaitThen (%test%)
#5 main.<anonymous closure> (%test%)
#6 runTest (harness.dart)
#7 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 noYields3 (%test%)
#2 noYields2 (%test%)
#3 noYields (%test%)
#4 doTestAwaitCatchError (%test%)
#5 main.<anonymous closure> (%test%)
#6 runTest (harness.dart)
#7 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 mixedYields2 (%test%)
<asynchronous suspension>
#2 mixedYields (%test%)
<asynchronous suspension>
#3 doTestAwait (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 mixedYields2 (%test%)
<asynchronous suspension>
#2 mixedYields (%test%)
<asynchronous suspension>
#3 doTestAwaitThen (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 mixedYields2 (%test%)
<asynchronous suspension>
#2 mixedYields (%test%)
<asynchronous suspension>
#3 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 syncSuffix2 (%test%)
<asynchronous suspension>
#2 syncSuffix (%test%)
<asynchronous suspension>
#3 doTestAwait (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 syncSuffix2 (%test%)
<asynchronous suspension>
#2 syncSuffix (%test%)
<asynchronous suspension>
#3 doTestAwaitThen (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 syncSuffix2 (%test%)
<asynchronous suspension>
#2 syncSuffix (%test%)
<asynchronous suspension>
#3 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 nonAsyncNoStack1 (%test%)
<asynchronous suspension>
#2 nonAsyncNoStack (%test%)
<asynchronous suspension>
#3 doTestAwait (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 nonAsyncNoStack1 (%test%)
<asynchronous suspension>
#2 nonAsyncNoStack (%test%)
<asynchronous suspension>
#3 doTestAwaitThen (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 nonAsyncNoStack1 (%test%)
<asynchronous suspension>
#2 nonAsyncNoStack (%test%)
<asynchronous suspension>
#3 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 asyncStarThrowSync (%test%)
<asynchronous suspension>
#2 awaitEveryAsyncStarThrowSync (%test%)
<asynchronous suspension>
#3 doTestAwait (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 asyncStarThrowSync (%test%)
<asynchronous suspension>
#2 awaitEveryAsyncStarThrowSync (%test%)
<asynchronous suspension>
#3 doTestAwaitThen (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 asyncStarThrowSync (%test%)
<asynchronous suspension>
#2 awaitEveryAsyncStarThrowSync (%test%)
<asynchronous suspension>
#3 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 asyncStarThrowAsync (%test%)
<asynchronous suspension>
#2 awaitEveryAsyncStarThrowAsync (%test%)
<asynchronous suspension>
#3 doTestAwait (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 asyncStarThrowAsync (%test%)
<asynchronous suspension>
#2 awaitEveryAsyncStarThrowAsync (%test%)
<asynchronous suspension>
#3 doTestAwaitThen (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 asyncStarThrowAsync (%test%)
<asynchronous suspension>
#2 awaitEveryAsyncStarThrowAsync (%test%)
<asynchronous suspension>
#3 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 asyncStarThrowAsync (%test%)
<asynchronous suspension>
#2 listenAsyncStarThrowAsync.<anonymous closure> (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 asyncStarThrowAsync (%test%)
<asynchronous suspension>
#2 listenAsyncStarThrowAsync.<anonymous closure> (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 asyncStarThrowAsync (%test%)
<asynchronous suspension>
#2 listenAsyncStarThrowAsync.<anonymous closure> (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 allYield3 (%test%)
<asynchronous suspension>
#2 allYield2 (%test%)
<asynchronous suspension>
#3 allYield (%test%)
<asynchronous suspension>
#4 customErrorZone.<anonymous closure> (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 allYield3 (%test%)
<asynchronous suspension>
#2 allYield2 (%test%)
<asynchronous suspension>
#3 allYield (%test%)
<asynchronous suspension>
#4 customErrorZone.<anonymous closure> (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 allYield3 (%test%)
<asynchronous suspension>
#2 allYield2 (%test%)
<asynchronous suspension>
#3 allYield (%test%)
<asynchronous suspension>
#4 customErrorZone.<anonymous closure> (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 Future.timeout.<anonymous closure> (future_impl.dart)
<asynchronous suspension>
#2 awaitTimeout (%test%)
<asynchronous suspension>
#3 doTestAwait (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 Future.timeout.<anonymous closure> (future_impl.dart)
<asynchronous suspension>
#2 awaitTimeout (%test%)
<asynchronous suspension>
#3 doTestAwaitThen (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 Future.timeout.<anonymous closure> (future_impl.dart)
<asynchronous suspension>
#2 awaitTimeout (%test%)
<asynchronous suspension>
#3 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 Future.wait.<anonymous closure> (future.dart)
<asynchronous suspension>
#2 awaitWait (%test%)
<asynchronous suspension>
#3 doTestAwait (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 Future.wait.<anonymous closure> (future.dart)
<asynchronous suspension>
#2 awaitWait (%test%)
<asynchronous suspension>
#3 doTestAwaitThen (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 Future.wait.<anonymous closure> (future.dart)
<asynchronous suspension>
#2 awaitWait (%test%)
<asynchronous suspension>
#3 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 doTestAwait (%test%)
<asynchronous suspension>
#2 runTest (harness.dart)
<asynchronous suspension>
#3 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 doTestAwaitThen (%test%)
<asynchronous suspension>
#2 runTest (harness.dart)
<asynchronous suspension>
#3 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#2 runTest (harness.dart)
<asynchronous suspension>
#3 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 futureThen.<anonymous closure> (%test%)
<asynchronous suspension>
#2 doTestAwait (%test%)
<asynchronous suspension>
#3 runTest (harness.dart)
<asynchronous suspension>
#4 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 futureThen.<anonymous closure> (%test%)
<asynchronous suspension>
#2 doTestAwaitThen (%test%)
<asynchronous suspension>
#3 runTest (harness.dart)
<asynchronous suspension>
#4 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 futureThen.<anonymous closure> (%test%)
<asynchronous suspension>
#2 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#3 runTest (harness.dart)
<asynchronous suspension>
#4 main (%test%)
<asynchronous suspension>"""
];
// CURRENT EXPECTATIONS END

View file

@ -0,0 +1,98 @@
// Copyright (c) 2023, 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.
//
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
// make this test pass on vm-aot-dwarf-* builders.
//
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
import 'dart:async';
import 'package:expect/expect.dart';
import 'harness.dart' as harness;
String effectOrder = '';
StackTrace? stackAfterYield = null;
void emit(String m) => effectOrder += m;
main() async {
if (harness.shouldSkip()) {
return;
}
harness.configure(currentExpectations);
await harness.runTest(() async {
emit('1');
await for (final value in produce()) {
emit('5');
Expect.equals('|value|', value);
}
emit('8');
Expect.equals('12345678', effectOrder);
effectOrder = '';
emit('1');
await for (final value in produceYieldStar()) {
emit('5');
Expect.equals('|value|', value);
break;
}
emit('6');
Expect.equals('123456', effectOrder);
return Future.error('error', stackAfterYield!);
});
harness.updateExpectations();
}
Stream<dynamic> produce() async* {
emit('2');
await for (String response in produceInner()) {
emit('4');
yield response;
}
emit('7');
}
Stream produceInner() async* {
emit('3');
yield '|value|';
emit('6');
stackAfterYield = StackTrace.current;
}
Stream<dynamic> produceYieldStar() async* {
emit('2');
await for (String response in produceInner()) {
emit('4');
yield response;
}
emit('x');
}
Stream produceInnerYieldStar() async* {
emit('3');
yield* Stream.fromIterable(['|value|', '|value2|']);
emit('x');
}
// CURRENT EXPECTATIONS BEGIN
final currentExpectations = [
"""
#0 produceInner (%test%)
<asynchronous suspension>
#1 produce (%test%)
<asynchronous suspension>
#2 main.<anonymous closure> (%test%)
<asynchronous suspension>
#3 runTest (harness.dart)
<asynchronous suspension>
#4 main (%test%)
<asynchronous suspension>"""
];
// CURRENT EXPECTATIONS END

View file

@ -0,0 +1,236 @@
// Copyright (c) 2023, 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.
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:expect/expect.dart';
import 'package:native_stack_traces/native_stack_traces.dart';
//
// Test framework
//
class _ParsedFrame {
const _ParsedFrame();
static _ParsedFrame parse(String frame) {
if (frame == '<asynchronous suspension>') {
return const _AsynchronousGap();
} else {
return _DartFrame.parse(frame);
}
}
}
class _DartFrame extends _ParsedFrame {
final int no;
final String symbol;
final String location;
final int? lineNo;
_DartFrame({
required this.no,
required this.symbol,
required this.location,
required this.lineNo,
});
static final _pattern = RegExp(
r'^#(?<no>\d+)\s+(?<symbol>[^(]+)(\((?<location>((\w+://)?[/\w]+:)?[^:]+)(:(?<line>\d+)(:(?<column>\d+))?)?\))?$');
static _DartFrame parse(String frame) {
final match = _pattern.firstMatch(frame);
if (match == null) {
throw 'Failed to parse: $frame';
}
final no = int.parse(match.namedGroup('no')!);
final symbol = match.namedGroup('symbol')!.trim();
var location = match.namedGroup('location')!;
if (location.endsWith('_test.dart')) {
location = '%test%';
}
final lineNo =
location.endsWith('utils.dart') || location.endsWith('tests.dart')
? match.namedGroup('line')
: null;
return _DartFrame(
no: no,
symbol: symbol,
location: location.split('/').last,
lineNo: lineNo != null ? int.parse(lineNo) : null,
);
}
@override
String toString() =>
'#$no $symbol ($location${lineNo != null ? ':$lineNo' : ''})';
@override
bool operator ==(Object other) {
if (other is! _DartFrame) {
return false;
}
return no == other.no &&
symbol == other.symbol &&
location == other.location &&
lineNo == other.lineNo;
}
}
class _AsynchronousGap extends _ParsedFrame {
const _AsynchronousGap();
@override
String toString() => '<asynchronous suspension>';
}
final _lineRE = RegExp(r'^(?:#(?<number>\d+)|<asynchronous suspension>)');
Future<List<_ParsedFrame>> _parseStack(String text) async {
if (text.contains('*** *** ***')) {
// Looks like DWARF stack traces mode.
text = await Stream.fromIterable(text.split('\n'))
.transform(DwarfStackTraceDecoder(_dwarf!))
.where(_lineRE.hasMatch)
.join('\n');
}
return text
.split('\n')
.map((l) => l.trim())
.where((l) => l.isNotEmpty)
.map(_ParsedFrame.parse)
.toList();
}
const _updatingExpectations = bool.fromEnvironment('update.expectations');
final _updatedExpectations = <String>[];
late final List<String> _currentExpectations;
var _testIndex = 0;
late final Dwarf? _dwarf;
void configure(List<String> currentExpectations,
{String debugInfoFilename = 'debug.so'}) {
if (debugInfoFilename != null) {
try {
final testCompilationDir = Platform.environment['TEST_COMPILATION_DIR'];
if (testCompilationDir != null) {
debugInfoFilename = path.join(testCompilationDir, debugInfoFilename);
}
_dwarf = Dwarf.fromFile(debugInfoFilename)!;
} on FileSystemException {
// We're not running in precompiled mode, so the file doesn't exist and
// we can continue normally.
}
}
_currentExpectations = currentExpectations;
}
Future<void> runTest(Future<void> Function() body) async {
try {
await body();
} catch (e, st) {
await checkExpectedStack(st);
}
}
Future<void> checkExpectedStack(StackTrace st) async {
final expectedFramesString = _testIndex < _currentExpectations.length
? _currentExpectations[_testIndex]
: '';
final stackTraceString = st.toString();
final gotFrames = await _parseStack(stackTraceString);
final normalizedStack = gotFrames.join('\n');
if (_updatingExpectations) {
_updatedExpectations.add(normalizedStack);
} else {
if (normalizedStack != expectedFramesString) {
final expectedFrames = await _parseStack(expectedFramesString);
final isDwarfMode = stackTraceString.contains('*** *** ***');
print('''
STACK TRACE MISMATCH -----------------
GOT:
$normalizedStack
EXPECTED:
$expectedFramesString
--------------------------------------
To regenate expectations run:
\$ ${Platform.executable} -Dupdate.expectations=true ${Platform.script}
--------------------------------------
''');
if (isDwarfMode) {
print('''
--------------------------------------
RAW STACK:
$st
--------------------------------------
''');
}
Expect.equals(
expectedFrames.length, gotFrames.length, 'wrong number of frames');
for (var i = 0; i < expectedFrames.length; i++) {
final expectedFrame = expectedFrames[i];
final gotFrame = gotFrames[i];
if (expectedFrame == gotFrame) {
continue;
}
if (expectedFrame is _DartFrame && gotFrame is _DartFrame) {
Expect.equals(expectedFrame.symbol, gotFrame.symbol,
'at frame #$i mismatched function name');
Expect.equals(expectedFrame.location, gotFrame.location,
'at frame #$i mismatched location');
Expect.equals(expectedFrame.lineNo, gotFrame.lineNo,
'at frame #$i mismatched line location');
}
Expect.equals(expectedFrame, gotFrame);
}
}
}
_testIndex++;
}
void updateExpectations([String? expectationsFile]) {
if (!_updatingExpectations) {
return;
}
final sourceFilePath = expectationsFile != null
? path.join(path.dirname(Platform.script.toFilePath()), expectationsFile)
: Platform.script.toFilePath();
final sourceFile = File(sourceFilePath);
final source = sourceFile.readAsStringSync();
final expectationsStart = source.lastIndexOf('// CURRENT EXPECTATIONS BEGIN');
final updatedExpectationsString =
[for (var s in _updatedExpectations) '"""\n$s"""'].join(",\n");
final newSource = source.substring(0, expectationsStart) +
"""
// CURRENT EXPECTATIONS BEGIN
final currentExpectations = [${updatedExpectationsString}];
// CURRENT EXPECTATIONS END
""";
sourceFile.writeAsStringSync(newSource);
print('updated expectations in ${sourceFile}!');
}
// Check if we are running with obfuscation but without DWARF stack traces
// then we don't have a way to deobfuscate the stack trace.
bool shouldSkip() {
final stack = StackTrace.current.toString();
return !stack.contains('shouldSkip') && !stack.contains('*** ***');
}

View file

@ -0,0 +1,57 @@
// Copyright (c) 2023, 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.
//
// This test ensures that "pkg:stack_trace" (used by "pkg:test") doesn't break
// when lazy async stacks are enabled by dropping frames below a synchronous
// start to an async function.
//
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
// make this test pass on vm-aot-dwarf-* builders.
//
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
import 'dart:async';
import 'package:test/test.dart';
import 'harness.dart' as harness;
Future<StackTrace> firstMethod() async {
return await secondMethod();
}
Future<StackTrace> secondMethod() async {
return StackTrace.current;
}
void main() {
if (harness.shouldSkip()) {
return;
}
setUpAll(() => harness.configure(currentExpectations));
test("Stacktrace includes sync-starts.", () async {
final st = await firstMethod();
await harness.checkExpectedStack(st);
});
tearDownAll(() => harness.updateExpectations());
}
// CURRENT EXPECTATIONS BEGIN
final currentExpectations = [
"""
#0 secondMethod (%test%)
#1 firstMethod (%test%)
#2 main.<anonymous closure> (%test%)
#3 Declarer.test.<anonymous closure>.<anonymous closure> (declarer.dart)
<asynchronous suspension>
#4 Declarer.test.<anonymous closure> (declarer.dart)
<asynchronous suspension>
#5 Invoker._waitForOutstandingCallbacks.<anonymous closure> (invoker.dart)
<asynchronous suspension>"""
];
// CURRENT EXPECTATIONS END

View file

@ -0,0 +1,102 @@
// Copyright (c) 2023, 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.
//
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
// make this test pass on vm-aot-dwarf-* builders.
//
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
import 'dart:async';
import 'package:expect/expect.dart';
import 'harness.dart' as harness;
bool barRunning = false;
Future<void> foo() async {}
Future<void> bar() async {
try {
barRunning = true;
await foo();
} finally {
barRunning = false;
}
}
Future<void> runTest() {
final Zone testZone = Zone.current.fork(
specification: ZoneSpecification(
registerUnaryCallback: _registerUnaryCallback,
registerBinaryCallback: _registerBinaryCallback));
return testZone.run(bar);
}
StackTrace? registerUnaryCallbackStackTrace;
StackTrace? registerBinaryCallbackStackTrace;
ZoneUnaryCallback<R, T> _registerUnaryCallback<R, T>(
Zone self, ZoneDelegate parent, Zone zone, R Function(T) f) {
final stackTrace = StackTrace.current;
print('registerUnaryCallback got stack trace:');
print(stackTrace);
if (barRunning) {
Expect.isNull(registerUnaryCallbackStackTrace);
registerUnaryCallbackStackTrace = stackTrace;
}
return parent.registerUnaryCallback(zone, f);
}
ZoneBinaryCallback<R, T1, T2> _registerBinaryCallback<R, T1, T2>(
Zone self, ZoneDelegate parent, Zone zone, R Function(T1, T2) f) {
final stackTrace = StackTrace.current;
print('registerBinaryCallback got stack trace:');
print(stackTrace);
if (barRunning) {
Expect.isNull(registerBinaryCallbackStackTrace);
registerBinaryCallbackStackTrace = stackTrace;
}
return parent.registerBinaryCallback(zone, f);
}
Future<void> main() async {
if (harness.shouldSkip()) {
return;
}
harness.configure(currentExpectations);
await runTest();
await harness.checkExpectedStack(registerUnaryCallbackStackTrace!);
await harness.checkExpectedStack(registerBinaryCallbackStackTrace!);
harness.updateExpectations();
}
// CURRENT EXPECTATIONS BEGIN
final currentExpectations = [
"""
#0 _registerUnaryCallback (%test%)
#1 _CustomZone.registerUnaryCallback (zone.dart)
#2 bar (%test%)
#3 _rootRun (zone.dart)
#4 _CustomZone.run (zone.dart)
#5 runTest (%test%)
#6 main (%test%)
#7 _delayEntrypointInvocation.<anonymous closure> (isolate_patch.dart)
#8 _RawReceivePort._handleMessage (isolate_patch.dart)""",
"""
#0 _registerBinaryCallback (%test%)
#1 _CustomZone.registerBinaryCallback (zone.dart)
#2 bar (%test%)
#3 _rootRun (zone.dart)
#4 _CustomZone.run (zone.dart)
#5 runTest (%test%)
#6 main (%test%)
#7 _delayEntrypointInvocation.<anonymous closure> (isolate_patch.dart)
#8 _RawReceivePort._handleMessage (isolate_patch.dart)"""
];
// CURRENT EXPECTATIONS END

View file

@ -1,17 +0,0 @@
// 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=--dwarf-stack-traces --save-debugging-info=async_lazy_debug.so
import 'dart:async';
import 'dart:io';
import 'utils.dart';
Future<void> main(List<String> args) async {
// We won't have access to the debugging info file on Android.
if (Platform.isAndroid) return;
await doTestsLazy('async_lazy_debug.so');
}

View file

@ -1,9 +0,0 @@
// Copyright (c) 2019, 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.
import 'dart:async';
import 'utils.dart';
Future<void> main(List<String> args) async => await doTestsLazy();

View file

@ -1,75 +0,0 @@
// Copyright (c) 2022, 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.
import 'dart:async';
import 'package:expect/expect.dart';
import 'utils.dart' show assertStack;
String effectOrder = '';
StackTrace? stackAfterYield = null;
void emit(String m) => effectOrder += m;
main() async {
emit('1');
await for (final value in produce()) {
emit('5');
Expect.equals('|value|', value);
}
emit('8');
Expect.equals('12345678', effectOrder);
assertStack(const <String>[
r'^#0 produceInner .*$',
r'^<asynchronous suspension>$',
r'^#1 produce .*$',
r'^<asynchronous suspension>$',
r'^#2 main .*$',
r'^<asynchronous suspension>$',
], stackAfterYield!);
effectOrder = '';
emit('1');
await for (final value in produceYieldStar()) {
emit('5');
Expect.equals('|value|', value);
break;
}
emit('6');
Expect.equals('123456', effectOrder);
}
Stream<dynamic> produce() async* {
emit('2');
await for (String response in produceInner()) {
emit('4');
yield response;
}
emit('7');
}
Stream produceInner() async* {
emit('3');
yield '|value|';
emit('6');
stackAfterYield = StackTrace.current;
}
Stream<dynamic> produceYieldStar() async* {
emit('2');
await for (String response in produceInner()) {
emit('4');
yield response;
}
emit('x');
}
Stream produceInnerYieldStar() async* {
emit('3');
yield* Stream.fromIterable(['|value|', '|value2|']);
emit('x');
}

View file

@ -1,27 +0,0 @@
// Copyright (c) 2019, 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.
//
// This test ensures that "pkg:stack_trace" (used by "pkg:test") doesn't break
// when lazy async stacks are enabled by dropping frames below a synchronous
// start to an async function.
import "package:test/test.dart";
import "package:stack_trace/src/stack_zone_specification.dart";
import 'dart:async';
void main() {
test("Stacktrace includes sync-starts.", () async {
final st = await firstMethod();
expect("$st", allOf([contains("firstMethod"), contains("secondMethod")]));
});
}
Future<StackTrace> firstMethod() async {
return await secondMethod();
}
Future<StackTrace> secondMethod() async {
return StackTrace.current;
}

View file

@ -1,865 +0,0 @@
// Copyright (c) 2019, 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.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:expect/expect.dart';
import 'package:native_stack_traces/native_stack_traces.dart';
// Test functions:
Future<void> throwSync() {
throw 'throw from throwSync';
}
Future<void> throwAsync() async {
await 0;
throw 'throw from throwAsync';
}
// ----
// Scenario: All async functions yielded at least once before throw:
// ----
Future<void> allYield() async {
await 0;
await allYield2();
}
Future<void> allYield2() async {
await 0;
await allYield3();
}
Future<void> allYield3() async {
await 0;
throwSync();
}
// ----
// Scenario: None of the async functions yielded before the throw:
// ----
Future<void> noYields() async {
await noYields2();
}
Future<void> noYields2() async {
await noYields3();
}
Future<void> noYields3() async {
throwSync();
}
// ----
// Scenario: Mixed yielding and non-yielding frames:
// ----
Future<void> mixedYields() async {
await mixedYields2();
}
Future<void> mixedYields2() async {
await 0;
await mixedYields3();
}
Future<void> mixedYields3() async {
return throwAsync();
}
// ----
// Scenario: Non-async frame:
// ----
Future<void> syncSuffix() async {
await syncSuffix2();
}
Future<void> syncSuffix2() async {
await 0;
await syncSuffix3();
}
Future<void> syncSuffix3() {
return throwAsync();
}
// ----
// Scenario: Caller is non-async, has no upwards stack:
// ----
Future nonAsyncNoStack() async => await nonAsyncNoStack1();
Future nonAsyncNoStack1() async => await nonAsyncNoStack2();
Future nonAsyncNoStack2() async => Future.value(0).then((_) => throwAsync());
// ----
// Scenario: async*:
// ----
Future awaitEveryAsyncStarThrowSync() async {
await for (Future v in asyncStarThrowSync()) {
await v;
}
}
Stream<Future> asyncStarThrowSync() async* {
for (int i = 0; i < 2; i++) {
await i;
yield throwSync();
}
}
Future awaitEveryAsyncStarThrowAsync() async {
await for (Future v in asyncStarThrowAsync()) {
await v;
}
}
Stream<Future> asyncStarThrowAsync() async* {
for (int i = 0; i < 2; i++) {
await i;
yield Future.value(i);
await throwAsync();
}
}
Future listenAsyncStarThrowAsync() async {
// Listening to an async* doesn't create the usual await-for StreamIterator.
StreamSubscription ss = asyncStarThrowAsync().listen((Future f) {});
await ss.asFuture();
}
// ----
// Scenario: All async functions yielded and we run in a custom zone with a
// custom error handler.
// ----
Future<void> customErrorZone() async {
final completer = Completer<void>();
runZonedGuarded(() async {
await allYield();
completer.complete(null);
}, (e, s) {
completer.completeError(e, s);
});
return completer.future;
}
// ----
// Scenario: Future.timeout:
// ----
Future awaitTimeout() async {
await (throwAsync().timeout(Duration(seconds: 1)));
}
// ----
// Scenario: Future.wait:
// ----
Future awaitWait() async {
await Future.wait([
throwAsync(),
() async {
await Future.value();
}()
]);
}
// ----
// Scenario: Future.whenComplete:
// ----
Future futureSyncWhenComplete() {
return Future.sync(throwAsync).whenComplete(() => 'nop');
}
// ----
// Scenario: Future.then:
// ----
Future futureThen() {
return Future.value(0).then((value) {
throwSync();
});
}
// Helpers:
// Marker to tell the matcher to ignore the rest of the stack.
const IGNORE_REMAINING_STACK = '#@ IGNORE_REMAINING_STACK #@';
// We want lines that either start with a frame index or an async gap marker.
final _lineRE = RegExp(r'^(?:#(?<number>\d+)|<asynchronous suspension>)');
Future<void> assertStack(List<String> expects, StackTrace stackTrace,
[String? debugInfoFilename]) async {
final original = await Stream.value(stackTrace.toString())
.transform(const LineSplitter())
.toList();
var frames = original;
// Use the DWARF stack decoder if we're running in --dwarf-stack-traces mode
// and in precompiled mode (otherwise --dwarf-stack-traces has no effect).
bool usingDwarf = false;
if (debugInfoFilename != null) {
try {
final dwarf = Dwarf.fromFile(debugInfoFilename)!;
usingDwarf = true;
frames = await Stream.fromIterable(original)
.transform(DwarfStackTraceDecoder(dwarf))
.where(_lineRE.hasMatch)
.toList();
} on FileSystemException {
// We're not running in precompiled mode, so the file doesn't exist and
// we can continue normally.
}
}
void printFrameInformation() {
print('RegExps for expected stack:');
expects.forEach((s) => print('"${s}"'));
print('');
if (usingDwarf) {
print('Non-symbolic actual stack:');
original.forEach(print);
print('');
}
print('Actual stack:');
frames.forEach(print);
print('');
}
for (int i = 0; i < expects.length; i++) {
try {
Expect.isTrue(i < frames.length,
'Expected at least ${expects.length} frames, found ${frames.length}');
} on ExpectException {
// On failed expect, print full stack for reference.
printFrameInformation();
print('Expected line ${i + 1} to be ${expects[i]} but was missing');
rethrow;
}
// If we encounter this special marker we ignore the rest of the stack.
if (expects[i] == IGNORE_REMAINING_STACK) {
return;
}
try {
Expect.isTrue(RegExp(expects[i]).hasMatch(frames[i]));
} on ExpectException {
// On failed expect, print full stack for reference.
printFrameInformation();
print('Expected line ${i + 1} to be `${expects[i]}` '
'but was `${frames[i]}`');
rethrow;
}
}
try {
Expect.equals(expects.length, frames.length);
} on ExpectException {
// On failed expect, print full stack for reference.
printFrameInformation();
rethrow;
}
}
Future<void> doTestAwait(Future f(), List<String> expectedStack,
[String? debugInfoFilename]) async {
// Caller catches exception.
try {
await f();
Expect.fail('No exception thrown!');
} on String catch (e, s) {
return assertStack(expectedStack, s, debugInfoFilename);
}
}
Future<void> doTestAwaitThen(Future f(), List<String> expectedStack,
[String? debugInfoFilename]) async {
// Caller catches but a then is set.
try {
// Passing (e) {} to then() can cause the closure instructions to be
// deduped, changing the stack trace to the deduped owner, so we
// duplicate the Expect.fail() call in the closure.
await f().then((e) => Expect.fail('No exception thrown!'));
Expect.fail('No exception thrown!');
} on String catch (e, s) {
return assertStack(expectedStack, s, debugInfoFilename);
}
}
Future<void> doTestAwaitCatchError(Future f(), List<String> expectedStack,
[String? debugInfoFilename]) async {
// Caller doesn't catch, but we have a catchError set.
late StackTrace stackTrace;
await f().catchError((e, s) {
stackTrace = s;
});
return assertStack(expectedStack, stackTrace, debugInfoFilename);
}
// ----
// Test "Suites":
// ----
Future<void> doTestsLazy([String? debugInfoFilename]) async {
// allYield
{
final allYieldExpected = const <String>[
r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$',
r'^#1 allYield3 \(.*/utils.dart:39(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#2 allYield2 \(.*/utils.dart:34(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#3 allYield \(.*/utils.dart:29(:3)?\)$',
r'^<asynchronous suspension>$',
];
await doTestAwait(
allYield,
allYieldExpected +
const <String>[
r'^#4 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#5 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#6 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
allYield,
allYieldExpected +
const <String>[
r'^#4 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#5 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#6 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
allYield,
allYieldExpected +
const <String>[
r'^#4 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#5 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#6 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// noYields
{
final noYieldsExpected = const <String>[
r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$',
r'^#1 noYields3 \(.*/utils.dart:54(:3)?\)$',
r'^#2 noYields2 \(.*/utils.dart:50(:9)?\)$',
r'^#3 noYields \(.*/utils.dart:46(:9)?\)$',
];
await doTestAwait(
noYields,
noYieldsExpected +
const <String>[
r'^#4 doTestAwait ',
r'^#5 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#6 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
noYields,
noYieldsExpected +
const <String>[
r'^#4 doTestAwaitThen ',
r'^#5 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#6 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
noYields,
noYieldsExpected +
const <String>[
r'^#4 doTestAwaitCatchError ',
r'^#5 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#6 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// mixedYields
{
final mixedYieldsExpected = const <String>[
r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#1 mixedYields2 \(.*/utils.dart:66(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#2 mixedYields \(.*/utils.dart:61(:3)?\)$',
r'^<asynchronous suspension>$',
];
await doTestAwait(
mixedYields,
mixedYieldsExpected +
const <String>[
r'^#3 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
mixedYields,
mixedYieldsExpected +
const <String>[
r'^#3 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
mixedYields,
mixedYieldsExpected +
const <String>[
r'^#3 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// syncSuffix
{
final syncSuffixExpected = const <String>[
r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#1 syncSuffix2 \(.*/utils.dart:82(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#2 syncSuffix \(.*/utils.dart:77(:3)?\)$',
r'^<asynchronous suspension>$',
];
await doTestAwait(
syncSuffix,
syncSuffixExpected +
const <String>[
r'^#3 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
syncSuffix,
syncSuffixExpected +
const <String>[
r'^#3 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
syncSuffix,
syncSuffixExpected +
const <String>[
r'^#3 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// nonAsyncNoStack
{
final nonAsyncNoStackExpected = const <String>[
r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#1 nonAsyncNoStack1 \(.*/utils.dart:95(:36)?\)$',
r'^<asynchronous suspension>$',
r'^#2 nonAsyncNoStack \(.*/utils.dart:93(:35)?\)$',
r'^<asynchronous suspension>$',
];
await doTestAwait(
nonAsyncNoStack,
nonAsyncNoStackExpected +
const <String>[
r'^#3 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
nonAsyncNoStack,
nonAsyncNoStackExpected +
const <String>[
r'^#3 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
nonAsyncNoStack,
nonAsyncNoStackExpected +
const <String>[
r'^#3 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// awaitEveryAsyncStarThrowSync
{
final asyncStarThrowSyncExpected = const <String>[
r'^#0 throwSync \(.+/utils.dart:16(:3)?\)$',
r'^#1 asyncStarThrowSync \(.+/utils.dart:112(:11)?\)$',
r'^<asynchronous suspension>$',
r'^#2 awaitEveryAsyncStarThrowSync \(.+/utils.dart:104(:3)?\)$',
r'^<asynchronous suspension>$',
];
await doTestAwait(
awaitEveryAsyncStarThrowSync,
asyncStarThrowSyncExpected +
const <String>[
r'^#3 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
awaitEveryAsyncStarThrowSync,
asyncStarThrowSyncExpected +
const <String>[
r'^#3 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
awaitEveryAsyncStarThrowSync,
asyncStarThrowSyncExpected +
const <String>[
r'^#3 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// awaitEveryAsyncStarThrowAsync
{
final asyncStarThrowAsyncExpected = const <String>[
r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#1 asyncStarThrowAsync \(.*/utils.dart:126(:5)?\)$',
r'^<asynchronous suspension>$',
r'^#2 awaitEveryAsyncStarThrowAsync \(.+/utils.dart:117(:3)?\)$',
r'^<asynchronous suspension>$',
];
await doTestAwait(
awaitEveryAsyncStarThrowAsync,
asyncStarThrowAsyncExpected +
const <String>[
r'^#3 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
awaitEveryAsyncStarThrowAsync,
asyncStarThrowAsyncExpected +
const <String>[
r'^#3 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
awaitEveryAsyncStarThrowAsync,
asyncStarThrowAsyncExpected +
const <String>[
r'^#3 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// listenAsyncStarThrowAsync
{
final listenAsyncStartExpected = const <String>[
r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#1 asyncStarThrowAsync \(.*/utils.dart:126(:5)?\)$',
r'^<asynchronous suspension>$',
r'^#2 listenAsyncStarThrowAsync.<anonymous closure> \(.+/utils.dart:132(:56)?\)$',
r'^<asynchronous suspension>$',
];
await doTestAwait(
listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename);
await doTestAwaitThen(
listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename);
await doTestAwaitCatchError(
listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename);
}
// customErrorZone
{
final customErrorZoneExpected = const <String>[
r'#0 throwSync \(.*/utils.dart:16(:3)?\)$',
r'#1 allYield3 \(.*/utils.dart:39(:3)?\)$',
r'<asynchronous suspension>$',
r'#2 allYield2 \(.*/utils.dart:34(:3)?\)$',
r'<asynchronous suspension>$',
r'#3 allYield \(.*/utils.dart:29(:3)?\)$',
r'<asynchronous suspension>$',
r'#4 customErrorZone.<anonymous closure> \(.*/utils.dart:144(:5)?\)$',
r'<asynchronous suspension>$',
];
await doTestAwait(
customErrorZone, customErrorZoneExpected, debugInfoFilename);
await doTestAwaitThen(
customErrorZone, customErrorZoneExpected, debugInfoFilename);
await doTestAwaitCatchError(
customErrorZone, customErrorZoneExpected, debugInfoFilename);
}
// awaitTimeout
{
final awaitTimeoutExpected = const <String>[
r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#1 Future.timeout.<anonymous closure> \(dart:async/future_impl.dart',
r'^<asynchronous suspension>$',
r'^#2 awaitTimeout ',
r'^<asynchronous suspension>$',
];
await doTestAwait(
awaitTimeout,
awaitTimeoutExpected +
const <String>[
r'^#3 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
awaitTimeout,
awaitTimeoutExpected +
const <String>[
r'^#3 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
awaitTimeout,
awaitTimeoutExpected +
const <String>[
r'^#3 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// awaitWait
{
final awaitWaitExpected = const <String>[
r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#1 Future.wait.<anonymous closure> \(dart:async/future.dart',
r'^<asynchronous suspension>$',
r'^#2 awaitWait ',
r'^<asynchronous suspension>$',
];
await doTestAwait(
awaitWait,
awaitWaitExpected +
const <String>[
r'^#3 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
awaitWait,
awaitWaitExpected +
const <String>[
r'^#3 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
awaitWait,
awaitWaitExpected +
const <String>[
r'^#3 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// futureSyncWhenComplete
{
final expected = const <String>[
r'^#0 throwAsync \(.*/utils.dart:21(:3)?\)$',
r'^<asynchronous suspension>$',
];
await doTestAwait(
futureSyncWhenComplete,
expected +
const <String>[
r'^#1 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#2 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#3 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
futureSyncWhenComplete,
expected +
const <String>[
r'^#1 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#2 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#3 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
futureSyncWhenComplete,
expected +
const <String>[
r'^#1 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#2 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#3 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// futureThen
{
final expected = const <String>[
r'^#0 throwSync \(.*/utils.dart:16(:3)?\)$',
r'^#1 futureThen.<anonymous closure> ',
r'^<asynchronous suspension>$',
];
await doTestAwait(
futureThen,
expected +
const <String>[
r'^#2 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#3 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#4 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
futureThen,
expected +
const <String>[
r'^#2 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#3 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#4 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
futureThen,
expected +
const <String>[
r'^#2 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#3 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#4 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
}

View file

@ -1,84 +0,0 @@
// Copyright (c) 2022, 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.
import 'dart:async';
import 'package:expect/expect.dart';
const String scriptName = 'zone_callback_stack_traces_test.dart';
Future<void> foo() async {}
Future<void> bar() async {
await foo();
}
Future<void> runTest() {
final Zone testZone = Zone.current.fork(
specification: ZoneSpecification(
registerUnaryCallback: _registerUnaryCallback,
registerBinaryCallback: _registerBinaryCallback));
return testZone.run(bar);
}
StackTrace? registerUnaryCallbackStackTrace;
StackTrace? registerBinaryCallbackStackTrace;
ZoneUnaryCallback<R, T> _registerUnaryCallback<R, T>(
Zone self, ZoneDelegate parent, Zone zone, R Function(T) f) {
final stackTrace = StackTrace.current;
print('registerUnaryCallback got stack trace:');
print(stackTrace);
if (stackTrace.toString().contains('bar')) {
Expect.isNull(registerUnaryCallbackStackTrace);
registerUnaryCallbackStackTrace = stackTrace;
}
return parent.registerUnaryCallback(zone, f);
}
ZoneBinaryCallback<R, T1, T2> _registerBinaryCallback<R, T1, T2>(
Zone self, ZoneDelegate parent, Zone zone, R Function(T1, T2) f) {
final stackTrace = StackTrace.current;
print('registerBinaryCallback got stack trace:');
print(stackTrace);
if (stackTrace.toString().contains('bar')) {
Expect.isNull(registerBinaryCallbackStackTrace);
registerBinaryCallbackStackTrace = stackTrace;
}
return parent.registerBinaryCallback(zone, f);
}
void verifyStackTrace(List<String> expected, StackTrace stackTrace) {
final List<String> actual = stackTrace
.toString()
.split('\n')
.where((entry) => entry.contains(scriptName))
.toList();
print('Expected:\n${expected.join('\n')}');
print('Actual:\n${actual.join('\n')}');
Expect.equals(expected.length, actual.length);
for (int i = 0; i < expected.length; ++i) {
if (!RegExp(expected[i]).hasMatch(actual[i])) {
Expect.fail("Stack trace entry $i doesn't match:\n"
" expected: ${expected[i]}\n actual: ${actual[i]}");
}
}
}
main() async {
await runTest();
verifyStackTrace([
r'^#\d+ _registerUnaryCallback \(.*zone_callback_stack_traces_test.dart:30(:33)?\)$',
r'^#\d+ bar \(.*zone_callback_stack_traces_test.dart:14(:3)?\)$',
r'^#\d+ runTest \(.*zone_callback_stack_traces_test.dart:22(:19)?\)$',
r'^#\d+ main \(.*zone_callback_stack_traces_test.dart:70(:9)?\)$',
], registerUnaryCallbackStackTrace!);
verifyStackTrace([
r'^#\d+ _registerBinaryCallback \(.*zone_callback_stack_traces_test.dart:42(:33)?\)$',
r'^#\d+ bar \(.*zone_callback_stack_traces_test.dart:14(:3)?\)$',
r'^#\d+ runTest \(.*zone_callback_stack_traces_test.dart:22(:19)?\)$',
r'^#\d+ main \(.*zone_callback_stack_traces_test.dart:70(:9)?\)$',
], registerBinaryCallbackStackTrace!);
}

View file

@ -1,8 +1,14 @@
// Copyright (c) 2023, 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.
//
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
// make this test pass on vm-aot-dwarf-* builders.
//
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
import 'causal_stacks/utils.dart' show assertStack, IGNORE_REMAINING_STACK;
import 'awaiter_stacks/harness.dart' as harness;
class A {
void takesA(A a) {
@ -18,7 +24,9 @@ class B extends A {
StackTrace? trace = null;
void main() {
void main() async {
harness.configure(currentExpectations);
A a = new A();
A b = new B();
try {
@ -26,9 +34,17 @@ void main() {
} catch (e, st) {
trace = st;
}
assertStack(const <String>[
r'^#0 B.takesA \(.*/checked_parameter_assert_assignable_stacktrace_test.dart:14(:27)?\)$',
r'^#1 main \(.*/checked_parameter_assert_assignable_stacktrace_test.dart:25(:7)?\)$',
IGNORE_REMAINING_STACK,
], trace!);
await harness.checkExpectedStack(trace!);
harness.updateExpectations();
}
// CURRENT EXPECTATIONS BEGIN
final currentExpectations = [
"""
#0 B.takesA (%test%)
#1 main (%test%)
#2 _delayEntrypointInvocation.<anonymous closure> (isolate_patch.dart)
#3 _RawReceivePort._handleMessage (isolate_patch.dart)"""
];
// CURRENT EXPECTATIONS END

View file

@ -2,57 +2,32 @@
// 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.
import 'causal_stacks/utils.dart';
import 'awaiter_stacks/harness.dart' as harness;
main() async {
harness.configure(currentExpectations);
StackTrace trace = StackTrace.empty;
A.visible(() => trace = StackTrace.current);
await assertStack([
r'^#0 main.<anonymous closure>',
r'^#1 new A.visible',
r'^#2 main',
IGNORE_REMAINING_STACK,
], trace);
await harness.checkExpectedStack(trace);
A.invisible(() => trace = StackTrace.current);
await assertStack([
r'^#0 main.<anonymous closure>',
r'^#1 main',
IGNORE_REMAINING_STACK,
], trace);
await harness.checkExpectedStack(trace);
visible(() => trace = StackTrace.current);
await assertStack([
r'^#0 main.<anonymous closure>',
r'^#1 visible',
r'^#2 main',
IGNORE_REMAINING_STACK,
], trace);
await harness.checkExpectedStack(trace);
invisible(() => trace = StackTrace.current);
await assertStack([
r'^#0 main.<anonymous closure>',
r'^#1 main',
IGNORE_REMAINING_STACK,
], trace);
await harness.checkExpectedStack(trace);
visibleClosure(() => trace = StackTrace.current);
await assertStack([
r'^#0 main.<anonymous closure>',
r'^#1 visibleClosure.visibleInner',
r'^#2 visibleClosure',
r'^#3 main',
IGNORE_REMAINING_STACK,
], trace);
await harness.checkExpectedStack(trace);
invisibleClosure(() => trace = StackTrace.current);
await assertStack([
r'^#0 main.<anonymous closure>',
r'^#1 invisibleClosure',
r'^#2 main',
IGNORE_REMAINING_STACK,
], trace);
await harness.checkExpectedStack(trace);
harness.updateExpectations();
}
class A {
@ -87,3 +62,38 @@ void invisibleClosure(void Function() fun) {
invisibleInner();
}
// CURRENT EXPECTATIONS BEGIN
final currentExpectations = [
"""
#0 main.<anonymous closure> (%test%)
#1 new A.visible (%test%)
#2 main (%test%)
#3 _delayEntrypointInvocation.<anonymous closure> (isolate_patch.dart)
#4 _RawReceivePort._handleMessage (isolate_patch.dart)""",
"""
#0 main.<anonymous closure> (%test%)
#1 main (%test%)
<asynchronous suspension>""",
"""
#0 main.<anonymous closure> (%test%)
#1 visible (%test%)
#2 main (%test%)
<asynchronous suspension>""",
"""
#0 main.<anonymous closure> (%test%)
#1 main (%test%)
<asynchronous suspension>""",
"""
#0 main.<anonymous closure> (%test%)
#1 visibleClosure.visibleInner (%test%)
#2 visibleClosure (%test%)
#3 main (%test%)
<asynchronous suspension>""",
"""
#0 main.<anonymous closure> (%test%)
#1 invisibleClosure (%test%)
#2 main (%test%)
<asynchronous suspension>"""
];
// CURRENT EXPECTATIONS END

View file

@ -1,95 +1,46 @@
// 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.
//
// This test checks that --resolve-dwarf-paths outputs absolute and relative
// paths in DWARF information.
// OtherResources=use_save_debugging_info_flag_program.dart
//
// VMOptions=--dwarf-stack-traces --resolve-dwarf-paths --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
import "dart:async";
import "dart:io";
import 'package:expect/expect.dart';
import 'package:native_stack_traces/native_stack_traces.dart';
import 'package:path/path.dart' as path;
import 'package:path/path.dart' as p;
import 'use_flag_test_helper.dart';
main(List<String> args) async {
if (!isAOTRuntime) {
return; // Running in JIT: AOT binaries not available.
}
if (Platform.isAndroid) {
return; // SDK tree and dart_bootstrap not available on the test device.
return;
}
// These are the tools we need to be available to run on a given platform:
if (!await testExecutable(genSnapshot)) {
throw "Cannot run test as $genSnapshot not available";
}
if (!await testExecutable(dartPrecompiledRuntime)) {
throw "Cannot run test as $dartPrecompiledRuntime not available";
}
if (!File(platformDill).existsSync()) {
throw "Cannot run test as $platformDill does not exist";
final isDwarfStackTraces = StackTrace.current.toString().contains('*** ***');
if (!isDwarfStackTraces) {
return;
}
runTests(obfuscate: false);
runTests(obfuscate: true);
}
final dwarfPath =
p.join(Platform.environment['TEST_COMPILATION_DIR']!, 'debug.so');
final dwarf = Dwarf.fromFile(dwarfPath)!;
void runTests({required bool obfuscate}) async {
final pathSuffix = obfuscate ? 'obfuscated' : 'cleartext';
await withTempDir('dwarf-flag-test-$pathSuffix', (String tempDir) async {
final cwDir = path.dirname(Platform.script.toFilePath());
final script =
path.join(cwDir, 'use_save_debugging_info_flag_program.dart');
final scriptDill = path.join(tempDir, 'flag_program.dill');
// Compile script to Kernel IR.
await run(genKernel, <String>[
'--aot',
'--platform=$platformDill',
'-o',
scriptDill,
script,
]);
final scriptDwarfSnapshot = path.join(tempDir, 'dwarf.so');
await run(genSnapshot, <String>[
if (obfuscate) ...[
'--obfuscate',
'--save-obfuscation-map=${path.join(tempDir, 'obfuscation.map')}',
],
'--resolve-dwarf-paths',
'--dwarf-stack-traces-mode',
'--snapshot-kind=app-aot-elf',
'--elf=$scriptDwarfSnapshot',
scriptDill,
]);
// Run the resulting Dwarf-AOT compiled script.
final dwarfTrace = await runError(dartPrecompiledRuntime, <String>[
scriptDwarfSnapshot,
scriptDill,
]);
final tracePCOffsets = collectPCOffsets(dwarfTrace);
// Check that translating the DWARF stack trace (without internal frames)
// matches the symbolic stack trace.
final dwarf = Dwarf.fromFile(scriptDwarfSnapshot);
Expect.isNotNull(dwarf);
checkDwarfInfo(dwarf!, tracePCOffsets);
});
final stack = StackTrace.current.toString();
print(stack);
final offsets = collectPCOffsets(stack.split('\n'));
print(offsets);
checkDwarfInfo(dwarf, offsets);
}
void checkDwarfInfo(Dwarf dwarf, Iterable<PCOffset> offsets) {
final filenames = <String>{};
for (final offset in offsets) {
final callInfo = offset.callInfoFrom(dwarf);
final callInfo = offset.callInfoFrom(dwarf, includeInternalFrames: true);
Expect.isNotNull(callInfo);
Expect.isNotEmpty(callInfo!);
for (final e in callInfo) {
@ -97,7 +48,7 @@ void checkDwarfInfo(Dwarf dwarf, Iterable<PCOffset> offsets) {
final entry = e as DartCallInfo;
var filename = entry.filename;
if (!filename.startsWith('/')) {
filename = path.join(sdkDir, filename);
filename = p.join(sdkDir, filename);
}
if (filenames.add(filename)) {
Expect.isTrue(
@ -110,4 +61,6 @@ void checkDwarfInfo(Dwarf dwarf, Iterable<PCOffset> offsets) {
print('- ${filename}');
}
Expect.isNotEmpty(filenames);
Expect.isNotEmpty(filenames
.where((p) => p.endsWith('use_resolve_dwarf_paths_flag_test.dart')));
}

View file

@ -0,0 +1,714 @@
// Copyright (c) 2023, 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.
//
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
// make this test pass on vm-aot-dwarf-* builders.
//
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
// @dart=2.9
import 'dart:async';
import 'package:expect/expect.dart';
import 'harness.dart' as harness;
// Test functions:
Future<void> throwSync() {
throw 'throw from throwSync';
}
Future<void> throwAsync() async {
await 0;
throw 'throw from throwAsync';
}
// ----
// Scenario: All async functions yielded at least once before throw:
// ----
Future<void> allYield() async {
await 0;
await allYield2();
}
Future<void> allYield2() async {
await 0;
await allYield3();
}
Future<void> allYield3() async {
await 0;
throwSync();
}
// ----
// Scenario: None of the async functions yielded before the throw:
// ----
Future<void> noYields() async {
await noYields2();
}
Future<void> noYields2() async {
await noYields3();
}
Future<void> noYields3() async {
throwSync();
}
// ----
// Scenario: Mixed yielding and non-yielding frames:
// ----
Future<void> mixedYields() async {
await mixedYields2();
}
Future<void> mixedYields2() async {
await 0;
await mixedYields3();
}
Future<void> mixedYields3() async {
return throwAsync();
}
// ----
// Scenario: Non-async frame:
// ----
Future<void> syncSuffix() async {
await syncSuffix2();
}
Future<void> syncSuffix2() async {
await 0;
await syncSuffix3();
}
Future<void> syncSuffix3() {
return throwAsync();
}
// ----
// Scenario: Caller is non-async, has no upwards stack:
// ----
Future nonAsyncNoStack() async => await nonAsyncNoStack1();
Future nonAsyncNoStack1() async => await nonAsyncNoStack2();
Future nonAsyncNoStack2() async => Future.value(0).then((_) => throwAsync());
// ----
// Scenario: async*:
// ----
Future awaitEveryAsyncStarThrowSync() async {
await for (Future v in asyncStarThrowSync()) {
await v;
}
}
Stream<Future> asyncStarThrowSync() async* {
for (int i = 0; i < 2; i++) {
await i;
yield throwSync();
}
}
Future awaitEveryAsyncStarThrowAsync() async {
await for (Future v in asyncStarThrowAsync()) {
await v;
}
}
Stream<Future> asyncStarThrowAsync() async* {
for (int i = 0; i < 2; i++) {
await i;
yield Future.value(i);
await throwAsync();
}
}
Future listenAsyncStarThrowAsync() async {
final _output = [];
// Listening to an async* doesn't create the usual await-for StreamIterator.
StreamSubscription ss = asyncStarThrowAsync().listen((Future f) {
_output.add('unique value');
});
await ss.asFuture();
if (_output.length == 44) {
print(_output);
}
}
// ----
// Scenario: All async functions yielded and we run in a custom zone with a
// custom error handler.
// ----
Future<void> customErrorZone() async {
final completer = Completer<void>();
runZonedGuarded(() async {
await allYield();
completer.complete(null);
}, (e, s) {
completer.completeError(e, s);
});
return completer.future;
}
// ----
// Scenario: Future.timeout:
// ----
Future awaitTimeout() async {
await (throwAsync().timeout(Duration(seconds: 1)));
}
// ----
// Scenario: Future.wait:
// ----
Future awaitWait() async {
await Future.wait([
throwAsync(),
() async {
await Future.value();
}()
]);
}
// ----
// Scenario: Future.whenComplete:
// ----
Future futureSyncWhenComplete() {
return Future.sync(throwAsync).whenComplete(() => 'nop');
}
// ----
// Scenario: Future.then:
// ----
Future futureThen() {
return Future.value(0).then((value) {
throwSync();
}).then(_doSomething);
}
void _doSomething(_) {
Expect.fail('Should not reach doSomething');
}
Future<void> doTestAwait(Future f()) async {
await f();
Expect.fail('No exception thrown!');
}
Future<void> doTestAwaitThen(Future f()) async {
// Passing (e) {} to then() can cause the closure instructions to be
// deduped, changing the stack trace to the deduped owner, so we
// duplicate the Expect.fail() call in the closure.
await f().then((e) => Expect.fail('No exception thrown!'));
}
Future<void> doTestAwaitCatchError(Future f()) async {
Object error;
StackTrace stackTrace;
await f().catchError((e, s) {
error = e;
stackTrace = s;
});
return Future.error(error, stackTrace);
}
Future<void> main(List<String> args) async {
if (harness.shouldSkip()) {
return;
}
harness.configure(currentExpectations);
final tests = [
allYield,
noYields,
mixedYields,
syncSuffix,
nonAsyncNoStack,
awaitEveryAsyncStarThrowSync,
awaitEveryAsyncStarThrowAsync,
listenAsyncStarThrowAsync,
customErrorZone,
awaitTimeout,
awaitWait,
futureSyncWhenComplete,
futureThen,
];
for (var test in tests) {
await harness.runTest(() => doTestAwait(test));
await harness.runTest(() => doTestAwaitThen(test));
await harness.runTest(() => doTestAwaitCatchError(test));
}
harness.updateExpectations();
}
// CURRENT EXPECTATIONS BEGIN
final currentExpectations = [
"""
#0 throwSync (%test%)
#1 allYield3 (%test%)
<asynchronous suspension>
#2 allYield2 (%test%)
<asynchronous suspension>
#3 allYield (%test%)
<asynchronous suspension>
#4 doTestAwait (%test%)
<asynchronous suspension>
#5 runTest (harness.dart)
<asynchronous suspension>
#6 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 allYield3 (%test%)
<asynchronous suspension>
#2 allYield2 (%test%)
<asynchronous suspension>
#3 allYield (%test%)
<asynchronous suspension>
#4 doTestAwaitThen (%test%)
<asynchronous suspension>
#5 runTest (harness.dart)
<asynchronous suspension>
#6 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 allYield3 (%test%)
<asynchronous suspension>
#2 allYield2 (%test%)
<asynchronous suspension>
#3 allYield (%test%)
<asynchronous suspension>
#4 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#5 runTest (harness.dart)
<asynchronous suspension>
#6 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 noYields3 (%test%)
#2 noYields2 (%test%)
#3 noYields (%test%)
#4 doTestAwait (%test%)
#5 main.<anonymous closure> (%test%)
#6 runTest (harness.dart)
#7 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 noYields3 (%test%)
#2 noYields2 (%test%)
#3 noYields (%test%)
#4 doTestAwaitThen (%test%)
#5 main.<anonymous closure> (%test%)
#6 runTest (harness.dart)
#7 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 noYields3 (%test%)
#2 noYields2 (%test%)
#3 noYields (%test%)
#4 doTestAwaitCatchError (%test%)
#5 main.<anonymous closure> (%test%)
#6 runTest (harness.dart)
#7 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 mixedYields2 (%test%)
<asynchronous suspension>
#2 mixedYields (%test%)
<asynchronous suspension>
#3 doTestAwait (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 mixedYields2 (%test%)
<asynchronous suspension>
#2 mixedYields (%test%)
<asynchronous suspension>
#3 doTestAwaitThen (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 mixedYields2 (%test%)
<asynchronous suspension>
#2 mixedYields (%test%)
<asynchronous suspension>
#3 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 syncSuffix2 (%test%)
<asynchronous suspension>
#2 syncSuffix (%test%)
<asynchronous suspension>
#3 doTestAwait (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 syncSuffix2 (%test%)
<asynchronous suspension>
#2 syncSuffix (%test%)
<asynchronous suspension>
#3 doTestAwaitThen (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 syncSuffix2 (%test%)
<asynchronous suspension>
#2 syncSuffix (%test%)
<asynchronous suspension>
#3 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 nonAsyncNoStack1 (%test%)
<asynchronous suspension>
#2 nonAsyncNoStack (%test%)
<asynchronous suspension>
#3 doTestAwait (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 nonAsyncNoStack1 (%test%)
<asynchronous suspension>
#2 nonAsyncNoStack (%test%)
<asynchronous suspension>
#3 doTestAwaitThen (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 nonAsyncNoStack1 (%test%)
<asynchronous suspension>
#2 nonAsyncNoStack (%test%)
<asynchronous suspension>
#3 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 asyncStarThrowSync (%test%)
<asynchronous suspension>
#2 awaitEveryAsyncStarThrowSync (%test%)
<asynchronous suspension>
#3 doTestAwait (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 asyncStarThrowSync (%test%)
<asynchronous suspension>
#2 awaitEveryAsyncStarThrowSync (%test%)
<asynchronous suspension>
#3 doTestAwaitThen (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 asyncStarThrowSync (%test%)
<asynchronous suspension>
#2 awaitEveryAsyncStarThrowSync (%test%)
<asynchronous suspension>
#3 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 asyncStarThrowAsync (%test%)
<asynchronous suspension>
#2 awaitEveryAsyncStarThrowAsync (%test%)
<asynchronous suspension>
#3 doTestAwait (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 asyncStarThrowAsync (%test%)
<asynchronous suspension>
#2 awaitEveryAsyncStarThrowAsync (%test%)
<asynchronous suspension>
#3 doTestAwaitThen (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 asyncStarThrowAsync (%test%)
<asynchronous suspension>
#2 awaitEveryAsyncStarThrowAsync (%test%)
<asynchronous suspension>
#3 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 asyncStarThrowAsync (%test%)
<asynchronous suspension>
#2 listenAsyncStarThrowAsync.<anonymous closure> (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 asyncStarThrowAsync (%test%)
<asynchronous suspension>
#2 listenAsyncStarThrowAsync.<anonymous closure> (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 asyncStarThrowAsync (%test%)
<asynchronous suspension>
#2 listenAsyncStarThrowAsync.<anonymous closure> (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 allYield3 (%test%)
<asynchronous suspension>
#2 allYield2 (%test%)
<asynchronous suspension>
#3 allYield (%test%)
<asynchronous suspension>
#4 customErrorZone.<anonymous closure> (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 allYield3 (%test%)
<asynchronous suspension>
#2 allYield2 (%test%)
<asynchronous suspension>
#3 allYield (%test%)
<asynchronous suspension>
#4 customErrorZone.<anonymous closure> (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 allYield3 (%test%)
<asynchronous suspension>
#2 allYield2 (%test%)
<asynchronous suspension>
#3 allYield (%test%)
<asynchronous suspension>
#4 customErrorZone.<anonymous closure> (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 Future.timeout.<anonymous closure> (future_impl.dart)
<asynchronous suspension>
#2 awaitTimeout (%test%)
<asynchronous suspension>
#3 doTestAwait (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 Future.timeout.<anonymous closure> (future_impl.dart)
<asynchronous suspension>
#2 awaitTimeout (%test%)
<asynchronous suspension>
#3 doTestAwaitThen (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 Future.timeout.<anonymous closure> (future_impl.dart)
<asynchronous suspension>
#2 awaitTimeout (%test%)
<asynchronous suspension>
#3 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 Future.wait.<anonymous closure> (future.dart)
<asynchronous suspension>
#2 awaitWait (%test%)
<asynchronous suspension>
#3 doTestAwait (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 Future.wait.<anonymous closure> (future.dart)
<asynchronous suspension>
#2 awaitWait (%test%)
<asynchronous suspension>
#3 doTestAwaitThen (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 Future.wait.<anonymous closure> (future.dart)
<asynchronous suspension>
#2 awaitWait (%test%)
<asynchronous suspension>
#3 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#4 runTest (harness.dart)
<asynchronous suspension>
#5 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 doTestAwait (%test%)
<asynchronous suspension>
#2 runTest (harness.dart)
<asynchronous suspension>
#3 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 doTestAwaitThen (%test%)
<asynchronous suspension>
#2 runTest (harness.dart)
<asynchronous suspension>
#3 main (%test%)
<asynchronous suspension>""",
"""
#0 throwAsync (%test%)
<asynchronous suspension>
#1 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#2 runTest (harness.dart)
<asynchronous suspension>
#3 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 futureThen.<anonymous closure> (%test%)
<asynchronous suspension>
#2 doTestAwait (%test%)
<asynchronous suspension>
#3 runTest (harness.dart)
<asynchronous suspension>
#4 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 futureThen.<anonymous closure> (%test%)
<asynchronous suspension>
#2 doTestAwaitThen (%test%)
<asynchronous suspension>
#3 runTest (harness.dart)
<asynchronous suspension>
#4 main (%test%)
<asynchronous suspension>""",
"""
#0 throwSync (%test%)
#1 futureThen.<anonymous closure> (%test%)
<asynchronous suspension>
#2 doTestAwaitCatchError (%test%)
<asynchronous suspension>
#3 runTest (harness.dart)
<asynchronous suspension>
#4 main (%test%)
<asynchronous suspension>"""
];
// CURRENT EXPECTATIONS END

View file

@ -0,0 +1,100 @@
// Copyright (c) 2023, 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.
//
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
// make this test pass on vm-aot-dwarf-* builders.
//
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
// @dart=2.9
import 'dart:async';
import 'package:expect/expect.dart';
import 'harness.dart' as harness;
String effectOrder = '';
StackTrace stackAfterYield = null;
void emit(String m) => effectOrder += m;
main() async {
if (harness.shouldSkip()) {
return;
}
harness.configure(currentExpectations);
await harness.runTest(() async {
emit('1');
await for (final value in produce()) {
emit('5');
Expect.equals('|value|', value);
}
emit('8');
Expect.equals('12345678', effectOrder);
effectOrder = '';
emit('1');
await for (final value in produceYieldStar()) {
emit('5');
Expect.equals('|value|', value);
break;
}
emit('6');
Expect.equals('123456', effectOrder);
return Future.error('error', stackAfterYield);
});
harness.updateExpectations();
}
Stream<dynamic> produce() async* {
emit('2');
await for (String response in produceInner()) {
emit('4');
yield response;
}
emit('7');
}
Stream produceInner() async* {
emit('3');
yield '|value|';
emit('6');
stackAfterYield = StackTrace.current;
}
Stream<dynamic> produceYieldStar() async* {
emit('2');
await for (String response in produceInner()) {
emit('4');
yield response;
}
emit('x');
}
Stream produceInnerYieldStar() async* {
emit('3');
yield* Stream.fromIterable(['|value|', '|value2|']);
emit('x');
}
// CURRENT EXPECTATIONS BEGIN
final currentExpectations = [
"""
#0 produceInner (%test%)
<asynchronous suspension>
#1 produce (%test%)
<asynchronous suspension>
#2 main.<anonymous closure> (%test%)
<asynchronous suspension>
#3 runTest (harness.dart)
<asynchronous suspension>
#4 main (%test%)
<asynchronous suspension>"""
];
// CURRENT EXPECTATIONS END

View file

@ -0,0 +1,237 @@
// Copyright (c) 2023, 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.
// @dart=2.9
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:expect/expect.dart';
import 'package:native_stack_traces/native_stack_traces.dart';
//
// Test framework
//
class _ParsedFrame {
const _ParsedFrame();
static _ParsedFrame parse(String frame) {
if (frame == '<asynchronous suspension>') {
return const _AsynchronousGap();
} else {
return _DartFrame.parse(frame);
}
}
}
class _DartFrame extends _ParsedFrame {
final int no;
final String symbol;
final String location;
final int lineNo;
_DartFrame({
this.no,
this.symbol,
this.location,
this.lineNo,
});
static final _pattern = RegExp(
r'^#(?<no>\d+)\s+(?<symbol>[^(]+)(\((?<location>((\w+://)?[/\w]+:)?[^:]+)(:(?<line>\d+)(:(?<column>\d+))?)?\))?$');
static _DartFrame parse(String frame) {
final match = _pattern.firstMatch(frame);
if (match == null) {
throw 'Failed to parse: $frame';
}
final no = int.parse(match.namedGroup('no'));
final symbol = match.namedGroup('symbol').trim();
var location = match.namedGroup('location');
if (location.endsWith('_test.dart')) {
location = '%test%';
}
final lineNo =
location.endsWith('utils.dart') || location.endsWith('tests.dart')
? match.namedGroup('line')
: null;
return _DartFrame(
no: no,
symbol: symbol,
location: location.split('/').last,
lineNo: lineNo != null ? int.parse(lineNo) : null,
);
}
@override
String toString() =>
'#$no $symbol ($location${lineNo != null ? ':$lineNo' : ''})';
@override
bool operator ==(Object other) {
if (other is _DartFrame) {
return no == other.no &&
symbol == other.symbol &&
location == other.location &&
lineNo == other.lineNo;
}
return false;
}
}
class _AsynchronousGap extends _ParsedFrame {
const _AsynchronousGap();
@override
String toString() => '<asynchronous suspension>';
}
final _lineRE = RegExp(r'^(?:#(?<number>\d+)|<asynchronous suspension>)');
Future<List<_ParsedFrame>> _parseStack(String text) async {
if (text.contains('*** *** ***')) {
// Looks like DWARF stack traces mode.
text = await Stream.fromIterable(text.split('\n'))
.transform(DwarfStackTraceDecoder(_dwarf))
.where(_lineRE.hasMatch)
.join('\n');
}
return text
.split('\n')
.map((l) => l.trim())
.where((l) => l.isNotEmpty)
.map(_ParsedFrame.parse)
.toList();
}
const _updatingExpectations = bool.fromEnvironment('update.expectations');
final _updatedExpectations = <String>[];
List<String> _currentExpectations;
var _testIndex = 0;
Dwarf _dwarf;
void configure(List<String> currentExpectations,
{String debugInfoFilename = 'debug.so'}) {
if (debugInfoFilename != null) {
try {
final testCompilationDir = Platform.environment['TEST_COMPILATION_DIR'];
if (testCompilationDir != null) {
debugInfoFilename = path.join(testCompilationDir, debugInfoFilename);
}
_dwarf = Dwarf.fromFile(debugInfoFilename);
} on FileSystemException {
// We're not running in precompiled mode, so the file doesn't exist and
// we can continue normally.
}
}
_currentExpectations = currentExpectations;
}
Future<void> runTest(Future<void> Function() body) async {
try {
await body();
} catch (e, st) {
await checkExpectedStack(st);
}
}
Future<void> checkExpectedStack(StackTrace st) async {
final expectedFramesString = _testIndex < _currentExpectations.length
? _currentExpectations[_testIndex]
: '';
final stackTraceString = st.toString();
final gotFrames = await _parseStack(stackTraceString);
final normalizedStack = gotFrames.join('\n');
if (_updatingExpectations) {
_updatedExpectations.add(normalizedStack);
} else {
if (normalizedStack != expectedFramesString) {
final expectedFrames = await _parseStack(expectedFramesString);
final isDwarfMode = stackTraceString.contains('*** *** ***');
print('''
STACK TRACE MISMATCH -----------------
GOT:
$normalizedStack
EXPECTED:
$expectedFramesString
--------------------------------------
To regenate expectations run:
\$ ${Platform.executable} -Dupdate.expectations=true ${Platform.script}
--------------------------------------
''');
if (isDwarfMode) {
print('''
--------------------------------------
RAW STACK:
$st
--------------------------------------
''');
}
Expect.equals(
expectedFrames.length, gotFrames.length, 'wrong number of frames');
for (var i = 0; i < expectedFrames.length; i++) {
final expectedFrame = expectedFrames[i];
final gotFrame = gotFrames[i];
if (expectedFrame == gotFrame) {
continue;
}
if (expectedFrame is _DartFrame && gotFrame is _DartFrame) {
Expect.equals(expectedFrame.symbol, gotFrame.symbol,
'at frame #$i mismatched function name');
Expect.equals(expectedFrame.location, gotFrame.location,
'at frame #$i mismatched location');
Expect.equals(expectedFrame.lineNo, gotFrame.lineNo,
'at frame #$i mismatched line location');
}
Expect.equals(expectedFrame, gotFrame);
}
}
}
_testIndex++;
}
void updateExpectations([String expectationsFile]) {
if (!_updatingExpectations) {
return;
}
final sourceFilePath = expectationsFile != null
? path.join(path.dirname(Platform.script.toFilePath()), expectationsFile)
: Platform.script.toFilePath();
final sourceFile = File(sourceFilePath);
final source = sourceFile.readAsStringSync();
final expectationsStart = source.lastIndexOf('// CURRENT EXPECTATIONS BEGIN');
final updatedExpectationsString =
[for (var s in _updatedExpectations) '"""\n$s"""'].join(",\n");
final newSource = source.substring(0, expectationsStart) +
"""
// CURRENT EXPECTATIONS BEGIN
final currentExpectations = [${updatedExpectationsString}];
// CURRENT EXPECTATIONS END
""";
sourceFile.writeAsStringSync(newSource);
print('updated expectations in ${sourceFile}!');
}
// Check if we are running with obfuscation but without DWARF stack traces
// then we don't have a way to deobfuscate the stack trace.
bool shouldSkip() {
final stack = StackTrace.current.toString();
return !stack.contains('shouldSkip') && !stack.contains('*** ***');
}

View file

@ -0,0 +1,59 @@
// Copyright (c) 2023, 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.
//
// This test ensures that "pkg:stack_trace" (used by "pkg:test") doesn't break
// when lazy async stacks are enabled by dropping frames below a synchronous
// start to an async function.
//
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
// make this test pass on vm-aot-dwarf-* builders.
//
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
// @dart=2.9
import 'dart:async';
import 'package:test/test.dart';
import 'harness.dart' as harness;
Future<StackTrace> firstMethod() async {
return await secondMethod();
}
Future<StackTrace> secondMethod() async {
return StackTrace.current;
}
void main() {
if (harness.shouldSkip()) {
return;
}
setUpAll(() => harness.configure(currentExpectations));
test("Stacktrace includes sync-starts.", () async {
final st = await firstMethod();
await harness.checkExpectedStack(st);
});
tearDownAll(() => harness.updateExpectations());
}
// CURRENT EXPECTATIONS BEGIN
final currentExpectations = [
"""
#0 secondMethod (%test%)
#1 firstMethod (%test%)
#2 main.<anonymous closure> (%test%)
#3 Declarer.test.<anonymous closure>.<anonymous closure> (declarer.dart)
<asynchronous suspension>
#4 Declarer.test.<anonymous closure> (declarer.dart)
<asynchronous suspension>
#5 Invoker._waitForOutstandingCallbacks.<anonymous closure> (invoker.dart)
<asynchronous suspension>"""
];
// CURRENT EXPECTATIONS END

View file

@ -0,0 +1,104 @@
// Copyright (c) 2023, 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.
//
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
// make this test pass on vm-aot-dwarf-* builders.
//
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
// @dart=2.9
import 'dart:async';
import 'package:expect/expect.dart';
import 'harness.dart' as harness;
bool barRunning = false;
Future<void> foo() async {}
Future<void> bar() async {
try {
barRunning = true;
await foo();
} finally {
barRunning = false;
}
}
Future<void> runTest() {
final Zone testZone = Zone.current.fork(
specification: ZoneSpecification(
registerUnaryCallback: _registerUnaryCallback,
registerBinaryCallback: _registerBinaryCallback));
return testZone.run(bar);
}
StackTrace registerUnaryCallbackStackTrace;
StackTrace registerBinaryCallbackStackTrace;
ZoneUnaryCallback<R, T> _registerUnaryCallback<R, T>(
Zone self, ZoneDelegate parent, Zone zone, R Function(T) f) {
final stackTrace = StackTrace.current;
print('registerUnaryCallback got stack trace:');
print(stackTrace);
if (barRunning) {
Expect.isNull(registerUnaryCallbackStackTrace);
registerUnaryCallbackStackTrace = stackTrace;
}
return parent.registerUnaryCallback(zone, f);
}
ZoneBinaryCallback<R, T1, T2> _registerBinaryCallback<R, T1, T2>(
Zone self, ZoneDelegate parent, Zone zone, R Function(T1, T2) f) {
final stackTrace = StackTrace.current;
print('registerBinaryCallback got stack trace:');
print(stackTrace);
if (barRunning) {
Expect.isNull(registerBinaryCallbackStackTrace);
registerBinaryCallbackStackTrace = stackTrace;
}
return parent.registerBinaryCallback(zone, f);
}
Future<void> main() async {
if (harness.shouldSkip()) {
return;
}
harness.configure(currentExpectations);
await runTest();
await harness.checkExpectedStack(registerUnaryCallbackStackTrace);
await harness.checkExpectedStack(registerBinaryCallbackStackTrace);
harness.updateExpectations();
}
// CURRENT EXPECTATIONS BEGIN
final currentExpectations = [
"""
#0 _registerUnaryCallback (%test%)
#1 _CustomZone.registerUnaryCallback (zone.dart)
#2 bar (%test%)
#3 _rootRun (zone.dart)
#4 _CustomZone.run (zone.dart)
#5 runTest (%test%)
#6 main (%test%)
#7 _delayEntrypointInvocation.<anonymous closure> (isolate_patch.dart)
#8 _RawReceivePort._handleMessage (isolate_patch.dart)""",
"""
#0 _registerBinaryCallback (%test%)
#1 _CustomZone.registerBinaryCallback (zone.dart)
#2 bar (%test%)
#3 _rootRun (zone.dart)
#4 _CustomZone.run (zone.dart)
#5 runTest (%test%)
#6 main (%test%)
#7 _delayEntrypointInvocation.<anonymous closure> (isolate_patch.dart)
#8 _RawReceivePort._handleMessage (isolate_patch.dart)"""
];
// CURRENT EXPECTATIONS END

View file

@ -1,19 +0,0 @@
// 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=--dwarf-stack-traces --save-debugging-info=async_lazy_debug.so
// @dart = 2.9
import 'dart:async';
import 'dart:io';
import 'utils.dart';
Future<void> main(List<String> args) async {
// We won't have access to the debugging info file on Android.
if (Platform.isAndroid) return;
await doTestsLazy('async_lazy_debug.so');
}

View file

@ -1,11 +0,0 @@
// Copyright (c) 2019, 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.
// @dart = 2.9
import 'dart:async';
import 'utils.dart';
Future<void> main(List<String> args) async => await doTestsLazy();

View file

@ -1,76 +0,0 @@
// Copyright (c) 2022, 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.
// @dart = 2.9
import 'dart:async';
import 'package:expect/expect.dart';
import 'utils.dart' show assertStack;
String effectOrder = '';
StackTrace stackAfterYield = null;
void emit(String m) => effectOrder += m;
main() async {
emit('1');
await for (final value in produce()) {
emit('5');
Expect.equals('|value|', value);
}
emit('8');
Expect.equals('12345678', effectOrder);
assertStack(const <String>[
r'^#0 produceInner .*$',
r'^<asynchronous suspension>$',
r'^#1 produce .*$',
r'^<asynchronous suspension>$',
r'^#2 main .*$',
r'^<asynchronous suspension>$',
], stackAfterYield);
effectOrder = '';
emit('1');
await for (final value in produceYieldStar()) {
emit('5');
Expect.equals('|value|', value);
break;
}
emit('6');
Expect.equals('123456', effectOrder);
}
Stream<dynamic> produce() async* {
emit('2');
await for (String response in produceInner()) {
emit('4');
yield response;
}
emit('7');
}
Stream produceInner() async* {
emit('3');
yield '|value|';
emit('6');
stackAfterYield = StackTrace.current;
}
Stream<dynamic> produceYieldStar() async* {
emit('2');
await for (String response in produceInner()) {
emit('4');
yield response;
}
emit('x');
}
Stream produceInnerYieldStar() async* {
emit('3');
yield* Stream.fromIterable(['|value|', '|value2|']);
emit('x');
}

View file

@ -1,29 +0,0 @@
// Copyright (c) 2019, 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.
//
// This test ensures that "pkg:stack_trace" (used by "pkg:test") doesn't break
// when lazy async stacks are enabled by dropping frames below a synchronous
// start to an async function.
// @dart = 2.9
import "package:test/test.dart";
import "package:stack_trace/src/stack_zone_specification.dart";
import 'dart:async';
void main() {
test("Stacktrace includes sync-starts.", () async {
final st = await firstMethod();
expect("$st", allOf([contains("firstMethod"), contains("secondMethod")]));
});
}
Future<StackTrace> firstMethod() async {
return await secondMethod();
}
Future<StackTrace> secondMethod() async {
return StackTrace.current;
}

View file

@ -1,867 +0,0 @@
// Copyright (c) 2019, 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.
// @dart = 2.9
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:expect/expect.dart';
import 'package:native_stack_traces/native_stack_traces.dart';
// Test functions:
Future<void> throwSync() {
throw 'throw from throwSync';
}
Future<void> throwAsync() async {
await 0;
throw 'throw from throwAsync';
}
// ----
// Scenario: All async functions yielded at least once before throw:
// ----
Future<void> allYield() async {
await 0;
await allYield2();
}
Future<void> allYield2() async {
await 0;
await allYield3();
}
Future<void> allYield3() async {
await 0;
throwSync();
}
// ----
// Scenario: None of the async functions yielded before the throw:
// ----
Future<void> noYields() async {
await noYields2();
}
Future<void> noYields2() async {
await noYields3();
}
Future<void> noYields3() async {
throwSync();
}
// ----
// Scenario: Mixed yielding and non-yielding frames:
// ----
Future<void> mixedYields() async {
await mixedYields2();
}
Future<void> mixedYields2() async {
await 0;
await mixedYields3();
}
Future<void> mixedYields3() async {
return throwAsync();
}
// ----
// Scenario: Non-async frame:
// ----
Future<void> syncSuffix() async {
await syncSuffix2();
}
Future<void> syncSuffix2() async {
await 0;
await syncSuffix3();
}
Future<void> syncSuffix3() {
return throwAsync();
}
// ----
// Scenario: Caller is non-async, has no upwards stack:
// ----
Future nonAsyncNoStack() async => await nonAsyncNoStack1();
Future nonAsyncNoStack1() async => await nonAsyncNoStack2();
Future nonAsyncNoStack2() async => Future.value(0).then((_) => throwAsync());
// ----
// Scenario: async*:
// ----
Future awaitEveryAsyncStarThrowSync() async {
await for (Future v in asyncStarThrowSync()) {
await v;
}
}
Stream<Future> asyncStarThrowSync() async* {
for (int i = 0; i < 2; i++) {
await i;
yield throwSync();
}
}
Future awaitEveryAsyncStarThrowAsync() async {
await for (Future v in asyncStarThrowAsync()) {
await v;
}
}
Stream<Future> asyncStarThrowAsync() async* {
for (int i = 0; i < 2; i++) {
await i;
yield Future.value(i);
await throwAsync();
}
}
Future listenAsyncStarThrowAsync() async {
// Listening to an async* doesn't create the usual await-for StreamIterator.
StreamSubscription ss = asyncStarThrowAsync().listen((Future f) => 42);
await ss.asFuture();
}
// ----
// Scenario: All async functions yielded and we run in a custom zone with a
// custom error handler.
// ----
Future<void> customErrorZone() async {
final completer = Completer<void>();
runZonedGuarded(() async {
await allYield();
completer.complete(null);
}, (e, s) {
completer.completeError(e, s);
});
return completer.future;
}
// ----
// Scenario: Future.timeout:
// ----
Future awaitTimeout() async {
await (throwAsync().timeout(Duration(seconds: 1)));
}
// ----
// Scenario: Future.wait:
// ----
Future awaitWait() async {
await Future.wait([
throwAsync(),
() async {
await Future.value();
}()
]);
}
// ----
// Scenario: Future.whenComplete:
// ----
Future futureSyncWhenComplete() {
return Future.sync(throwAsync).whenComplete(() => 'nop');
}
// ----
// Scenario: Future.then:
// ----
Future futureThen() {
return Future.value(0).then((value) {
throwSync();
});
}
// Helpers:
// Marker to tell the matcher to ignore the rest of the stack.
const IGNORE_REMAINING_STACK = '#@ IGNORE_REMAINING_STACK #@';
// We want lines that either start with a frame index or an async gap marker.
final _lineRE = RegExp(r'^(?:#(?<number>\d+)|<asynchronous suspension>)');
Future<void> assertStack(List<String> expects, StackTrace stackTrace,
[String debugInfoFilename]) async {
final original = await Stream.value(stackTrace.toString())
.transform(const LineSplitter())
.toList();
var frames = original;
// Use the DWARF stack decoder if we're running in --dwarf-stack-traces mode
// and in precompiled mode (otherwise --dwarf-stack-traces has no effect).
bool usingDwarf = false;
if (debugInfoFilename != null) {
try {
final dwarf = Dwarf.fromFile(debugInfoFilename);
usingDwarf = true;
frames = await Stream.fromIterable(original)
.transform(DwarfStackTraceDecoder(dwarf))
.where(_lineRE.hasMatch)
.toList();
} on FileSystemException {
// We're not running in precompiled mode, so the file doesn't exist and
// we can continue normally.
}
}
void printFrameInformation() {
print('RegExps for expected stack:');
expects.forEach((s) => print('"${s}"'));
print('');
if (usingDwarf) {
print('Non-symbolic actual stack:');
original.forEach(print);
print('');
}
print('Actual stack:');
frames.forEach(print);
print('');
}
for (int i = 0; i < expects.length; i++) {
try {
Expect.isTrue(i < frames.length,
'Expected at least ${expects.length} frames, found ${frames.length}');
} on ExpectException {
// On failed expect, print full stack for reference.
printFrameInformation();
print('Expected line ${i + 1} to be ${expects[i]} but was missing');
rethrow;
}
// If we encounter this special marker we ignore the rest of the stack.
if (expects[i] == IGNORE_REMAINING_STACK) {
return;
}
try {
Expect.isTrue(RegExp(expects[i]).hasMatch(frames[i]));
} on ExpectException {
// On failed expect, print full stack for reference.
printFrameInformation();
print('Expected line ${i + 1} to be `${expects[i]}` '
'but was `${frames[i]}`');
rethrow;
}
}
try {
Expect.equals(expects.length, frames.length);
} on ExpectException {
// On failed expect, print full stack for reference.
printFrameInformation();
rethrow;
}
}
Future<void> doTestAwait(Future f(), List<String> expectedStack,
[String debugInfoFilename]) async {
// Caller catches exception.
try {
await f();
Expect.fail('No exception thrown!');
} on String catch (e, s) {
return assertStack(expectedStack, s, debugInfoFilename);
}
}
Future<void> doTestAwaitThen(Future f(), List<String> expectedStack,
[String debugInfoFilename]) async {
// Caller catches but a then is set.
try {
// Passing (e) {} to then() can cause the closure instructions to be
// deduped, changing the stack trace to the deduped owner, so we
// duplicate the Expect.fail() call in the closure.
await f().then((e) => Expect.fail('No exception thrown!'));
Expect.fail('No exception thrown!');
} on String catch (e, s) {
return assertStack(expectedStack, s, debugInfoFilename);
}
}
Future<void> doTestAwaitCatchError(Future f(), List<String> expectedStack,
[String debugInfoFilename]) async {
// Caller doesn't catch, but we have a catchError set.
StackTrace stackTrace;
await f().catchError((e, s) {
stackTrace = s;
});
return assertStack(expectedStack, stackTrace, debugInfoFilename);
}
// ----
// Test "Suites":
// ----
Future<void> doTestsLazy([String debugInfoFilename]) async {
// allYield
{
final allYieldExpected = const <String>[
r'^#0 throwSync \(.*/utils.dart:18(:3)?\)$',
r'^#1 allYield3 \(.*/utils.dart:41(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#2 allYield2 \(.*/utils.dart:36(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#3 allYield \(.*/utils.dart:31(:3)?\)$',
r'^<asynchronous suspension>$',
];
await doTestAwait(
allYield,
allYieldExpected +
const <String>[
r'^#4 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#5 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#6 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
allYield,
allYieldExpected +
const <String>[
r'^#4 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#5 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#6 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
allYield,
allYieldExpected +
const <String>[
r'^#4 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#5 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#6 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// noYields
{
final noYieldsExpected = const <String>[
r'^#0 throwSync \(.*/utils.dart:18(:3)?\)$',
r'^#1 noYields3 \(.*/utils.dart:56(:3)?\)$',
r'^#2 noYields2 \(.*/utils.dart:52(:9)?\)$',
r'^#3 noYields \(.*/utils.dart:48(:9)?\)$',
];
await doTestAwait(
noYields,
noYieldsExpected +
const <String>[
r'^#4 doTestAwait ',
r'^#5 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#6 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
noYields,
noYieldsExpected +
const <String>[
r'^#4 doTestAwaitThen ',
r'^#5 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#6 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
noYields,
noYieldsExpected +
const <String>[
r'^#4 doTestAwaitCatchError ',
r'^#5 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#6 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// mixedYields
{
final mixedYieldsExpected = const <String>[
r'^#0 throwAsync \(.*/utils.dart:23(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#1 mixedYields2 \(.*/utils.dart:68(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#2 mixedYields \(.*/utils.dart:63(:3)?\)$',
r'^<asynchronous suspension>$',
];
await doTestAwait(
mixedYields,
mixedYieldsExpected +
const <String>[
r'^#3 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
mixedYields,
mixedYieldsExpected +
const <String>[
r'^#3 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
mixedYields,
mixedYieldsExpected +
const <String>[
r'^#3 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// syncSuffix
{
final syncSuffixExpected = const <String>[
r'^#0 throwAsync \(.*/utils.dart:23(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#1 syncSuffix2 \(.*/utils.dart:84(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#2 syncSuffix \(.*/utils.dart:79(:3)?\)$',
r'^<asynchronous suspension>$',
];
await doTestAwait(
syncSuffix,
syncSuffixExpected +
const <String>[
r'^#3 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
syncSuffix,
syncSuffixExpected +
const <String>[
r'^#3 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
syncSuffix,
syncSuffixExpected +
const <String>[
r'^#3 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// nonAsyncNoStack
{
final nonAsyncNoStackExpected = const <String>[
r'^#0 throwAsync \(.*/utils.dart:23(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#1 nonAsyncNoStack1 \(.*/utils.dart:97(:36)?\)$',
r'^<asynchronous suspension>$',
r'^#2 nonAsyncNoStack \(.*/utils.dart:95(:35)?\)$',
r'^<asynchronous suspension>$',
];
await doTestAwait(
nonAsyncNoStack,
nonAsyncNoStackExpected +
const <String>[
r'^#3 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
nonAsyncNoStack,
nonAsyncNoStackExpected +
const <String>[
r'^#3 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
nonAsyncNoStack,
nonAsyncNoStackExpected +
const <String>[
r'^#3 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// awaitEveryAsyncStarThrowSync
{
final asyncStarThrowSyncExpected = const <String>[
r'^#0 throwSync \(.+/utils.dart:18(:3)?\)$',
r'^#1 asyncStarThrowSync \(.+/utils.dart:114(:11)?\)$',
r'^<asynchronous suspension>$',
r'^#2 awaitEveryAsyncStarThrowSync \(.+/utils.dart:106(:3)?\)$',
r'^<asynchronous suspension>$',
];
await doTestAwait(
awaitEveryAsyncStarThrowSync,
asyncStarThrowSyncExpected +
const <String>[
r'^#3 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
awaitEveryAsyncStarThrowSync,
asyncStarThrowSyncExpected +
const <String>[
r'^#3 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
awaitEveryAsyncStarThrowSync,
asyncStarThrowSyncExpected +
const <String>[
r'^#3 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// awaitEveryAsyncStarThrowAsync
{
final asyncStarThrowAsyncExpected = const <String>[
r'^#0 throwAsync \(.*/utils.dart:23(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#1 asyncStarThrowAsync \(.*/utils.dart:128(:5)?\)$',
r'^<asynchronous suspension>$',
r'^#2 awaitEveryAsyncStarThrowAsync \(.+/utils.dart:119(:3)?\)$',
r'^<asynchronous suspension>$',
];
await doTestAwait(
awaitEveryAsyncStarThrowAsync,
asyncStarThrowAsyncExpected +
const <String>[
r'^#3 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
awaitEveryAsyncStarThrowAsync,
asyncStarThrowAsyncExpected +
const <String>[
r'^#3 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
awaitEveryAsyncStarThrowAsync,
asyncStarThrowAsyncExpected +
const <String>[
r'^#3 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// listenAsyncStarThrowAsync
{
final listenAsyncStartExpected = const <String>[
r'^#0 throwAsync \(.*/utils.dart:23(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#1 asyncStarThrowAsync \(.*/utils.dart:128(:5)?\)$',
r'^<asynchronous suspension>$',
r'^#2 listenAsyncStarThrowAsync.<anonymous closure> \(.+/utils.dart:134(:56)?\)$',
r'^<asynchronous suspension>$',
];
await doTestAwait(
listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename);
await doTestAwaitThen(
listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename);
await doTestAwaitCatchError(
listenAsyncStarThrowAsync, listenAsyncStartExpected, debugInfoFilename);
}
// customErrorZone
{
final customErrorZoneExpected = const <String>[
r'#0 throwSync \(.*/utils.dart:18(:3)?\)$',
r'#1 allYield3 \(.*/utils.dart:41(:3)?\)$',
r'<asynchronous suspension>$',
r'#2 allYield2 \(.*/utils.dart:36(:3)?\)$',
r'<asynchronous suspension>$',
r'#3 allYield \(.*/utils.dart:31(:3)?\)$',
r'<asynchronous suspension>$',
r'#4 customErrorZone.<anonymous closure> \(.*/utils.dart:146(:5)?\)$',
r'<asynchronous suspension>$',
];
await doTestAwait(
customErrorZone, customErrorZoneExpected, debugInfoFilename);
await doTestAwaitThen(
customErrorZone, customErrorZoneExpected, debugInfoFilename);
await doTestAwaitCatchError(
customErrorZone, customErrorZoneExpected, debugInfoFilename);
}
// awaitTimeout
{
final awaitTimeoutExpected = const <String>[
r'^#0 throwAsync \(.*/utils.dart:23(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#1 Future.timeout.<anonymous closure> \(dart:async/future_impl.dart',
r'^<asynchronous suspension>$',
r'^#2 awaitTimeout ',
r'^<asynchronous suspension>$',
];
await doTestAwait(
awaitTimeout,
awaitTimeoutExpected +
const <String>[
r'^#3 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
awaitTimeout,
awaitTimeoutExpected +
const <String>[
r'^#3 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
awaitTimeout,
awaitTimeoutExpected +
const <String>[
r'^#3 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// awaitWait
{
final awaitWaitExpected = const <String>[
r'^#0 throwAsync \(.*/utils.dart:23(:3)?\)$',
r'^<asynchronous suspension>$',
r'^#1 Future.wait.<anonymous closure> \(dart:async/future.dart',
r'^<asynchronous suspension>$',
r'^#2 awaitWait ',
r'^<asynchronous suspension>$',
];
await doTestAwait(
awaitWait,
awaitWaitExpected +
const <String>[
r'^#3 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
awaitWait,
awaitWaitExpected +
const <String>[
r'^#3 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
awaitWait,
awaitWaitExpected +
const <String>[
r'^#3 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#4 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#5 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// futureSyncWhenComplete
{
final expected = const <String>[
r'^#0 throwAsync \(.*/utils.dart:23(:3)?\)$',
r'^<asynchronous suspension>$',
];
await doTestAwait(
futureSyncWhenComplete,
expected +
const <String>[
r'^#1 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#2 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#3 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
futureSyncWhenComplete,
expected +
const <String>[
r'^#1 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#2 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#3 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
futureSyncWhenComplete,
expected +
const <String>[
r'^#1 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#2 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#3 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
// futureThen
{
final expected = const <String>[
r'^#0 throwSync \(.*/utils.dart:18(:3)?\)$',
r'^#1 futureThen.<anonymous closure> ',
r'^<asynchronous suspension>$',
];
await doTestAwait(
futureThen,
expected +
const <String>[
r'^#2 doTestAwait ',
r'^<asynchronous suspension>$',
r'^#3 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#4 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitThen(
futureThen,
expected +
const <String>[
r'^#2 doTestAwaitThen ',
r'^<asynchronous suspension>$',
r'^#3 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#4 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
await doTestAwaitCatchError(
futureThen,
expected +
const <String>[
r'^#2 doTestAwaitCatchError ',
r'^<asynchronous suspension>$',
r'^#3 doTestsLazy ',
r'^<asynchronous suspension>$',
r'^#4 main ',
r'^<asynchronous suspension>$',
],
debugInfoFilename);
}
}

View file

@ -1,86 +0,0 @@
// Copyright (c) 2022, 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.
// @dart = 2.9
import 'dart:async';
import 'package:expect/expect.dart';
const String scriptName = 'zone_callback_stack_traces_test.dart';
Future<void> foo() async {}
Future<void> bar() async {
await foo();
}
Future<void> runTest() {
final Zone testZone = Zone.current.fork(
specification: ZoneSpecification(
registerUnaryCallback: _registerUnaryCallback,
registerBinaryCallback: _registerBinaryCallback));
return testZone.run(bar);
}
StackTrace registerUnaryCallbackStackTrace;
StackTrace registerBinaryCallbackStackTrace;
ZoneUnaryCallback<R, T> _registerUnaryCallback<R, T>(
Zone self, ZoneDelegate parent, Zone zone, R Function(T) f) {
final stackTrace = StackTrace.current;
print('registerUnaryCallback got stack trace:');
print(stackTrace);
if (stackTrace.toString().contains('bar')) {
Expect.isNull(registerUnaryCallbackStackTrace);
registerUnaryCallbackStackTrace = stackTrace;
}
return parent.registerUnaryCallback(zone, f);
}
ZoneBinaryCallback<R, T1, T2> _registerBinaryCallback<R, T1, T2>(
Zone self, ZoneDelegate parent, Zone zone, R Function(T1, T2) f) {
final stackTrace = StackTrace.current;
print('registerBinaryCallback got stack trace:');
print(stackTrace);
if (stackTrace.toString().contains('bar')) {
Expect.isNull(registerBinaryCallbackStackTrace);
registerBinaryCallbackStackTrace = stackTrace;
}
return parent.registerBinaryCallback(zone, f);
}
void verifyStackTrace(List<String> expected, StackTrace stackTrace) {
final List<String> actual = stackTrace
.toString()
.split('\n')
.where((entry) => entry.contains(scriptName))
.toList();
print('Expected:\n${expected.join('\n')}');
print('Actual:\n${actual.join('\n')}');
Expect.equals(expected.length, actual.length);
for (int i = 0; i < expected.length; ++i) {
if (!RegExp(expected[i]).hasMatch(actual[i])) {
Expect.fail("Stack trace entry $i doesn't match:\n"
" expected: ${expected[i]}\n actual: ${actual[i]}");
}
}
}
main() async {
await runTest();
verifyStackTrace([
r'^#\d+ _registerUnaryCallback \(.*zone_callback_stack_traces_test.dart:32(:33)?\)$',
r'^#\d+ bar \(.*zone_callback_stack_traces_test.dart:16(:3)?\)$',
r'^#\d+ runTest \(.*zone_callback_stack_traces_test.dart:24(:19)?\)$',
r'^#\d+ main \(.*zone_callback_stack_traces_test.dart:72(:9)?\)$',
], registerUnaryCallbackStackTrace);
verifyStackTrace([
r'^#\d+ _registerBinaryCallback \(.*zone_callback_stack_traces_test.dart:44(:33)?\)$',
r'^#\d+ bar \(.*zone_callback_stack_traces_test.dart:16(:3)?\)$',
r'^#\d+ runTest \(.*zone_callback_stack_traces_test.dart:24(:19)?\)$',
r'^#\d+ main \(.*zone_callback_stack_traces_test.dart:72(:9)?\)$',
], registerBinaryCallbackStackTrace);
}

View file

@ -1,10 +1,16 @@
// Copyright (c) 2023, 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.
//
// Note: we pass --save-debugging-info=* without --dwarf-stack-traces to
// make this test pass on vm-aot-dwarf-* builders.
//
// VMOptions=--save-debugging-info=$TEST_COMPILATION_DIR/debug.so
// VMOptions=--dwarf-stack-traces --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
// @dart = 2.9
// @dart=2.9
import 'causal_stacks/utils.dart' show assertStack, IGNORE_REMAINING_STACK;
import 'awaiter_stacks/harness.dart' as harness;
class A {
void takesA(A a) {
@ -20,7 +26,9 @@ class B extends A {
StackTrace trace = null;
void main() {
void main() async {
harness.configure(currentExpectations);
A a = new A();
A b = new B();
try {
@ -28,9 +36,17 @@ void main() {
} catch (e, st) {
trace = st;
}
assertStack(const <String>[
r'^#0 B.takesA \(.*/checked_parameter_assert_assignable_stacktrace_test.dart:16(:27)?\)$',
r'^#1 main \(.*/checked_parameter_assert_assignable_stacktrace_test.dart:27(:7)?\)$',
IGNORE_REMAINING_STACK,
], trace);
await harness.checkExpectedStack(trace);
harness.updateExpectations();
}
// CURRENT EXPECTATIONS BEGIN
final currentExpectations = [
"""
#0 B.takesA (%test%)
#1 main (%test%)
#2 _delayEntrypointInvocation.<anonymous closure> (isolate_patch.dart)
#3 _RawReceivePort._handleMessage (isolate_patch.dart)"""
];
// CURRENT EXPECTATIONS END

View file

@ -4,57 +4,31 @@
// @dart = 2.9
import 'causal_stacks/utils.dart';
import 'awaiter_stacks/harness.dart' as harness;
main() async {
StackTrace trace = StackTrace.empty;
harness.configure(currentExpectations);
StackTrace trace = StackTrace.empty;
A.visible(() => trace = StackTrace.current);
await assertStack([
r'^#0 main.<anonymous closure>',
r'^#1 new A.visible',
r'^#2 main',
IGNORE_REMAINING_STACK,
], trace);
await harness.checkExpectedStack(trace);
A.invisible(() => trace = StackTrace.current);
await assertStack([
r'^#0 main.<anonymous closure>',
r'^#1 main',
IGNORE_REMAINING_STACK,
], trace);
await harness.checkExpectedStack(trace);
visible(() => trace = StackTrace.current);
await assertStack([
r'^#0 main.<anonymous closure>',
r'^#1 visible',
r'^#2 main',
IGNORE_REMAINING_STACK,
], trace);
await harness.checkExpectedStack(trace);
invisible(() => trace = StackTrace.current);
await assertStack([
r'^#0 main.<anonymous closure>',
r'^#1 main',
IGNORE_REMAINING_STACK,
], trace);
await harness.checkExpectedStack(trace);
visibleClosure(() => trace = StackTrace.current);
await assertStack([
r'^#0 main.<anonymous closure>',
r'^#1 visibleClosure.visibleInner',
r'^#2 visibleClosure',
r'^#3 main',
IGNORE_REMAINING_STACK,
], trace);
await harness.checkExpectedStack(trace);
invisibleClosure(() => trace = StackTrace.current);
await assertStack([
r'^#0 main.<anonymous closure>',
r'^#1 invisibleClosure',
r'^#2 main',
IGNORE_REMAINING_STACK,
], trace);
await harness.checkExpectedStack(trace);
harness.updateExpectations();
}
class A {
@ -89,3 +63,38 @@ void invisibleClosure(void Function() fun) {
invisibleInner();
}
// CURRENT EXPECTATIONS BEGIN
final currentExpectations = [
"""
#0 main.<anonymous closure> (%test%)
#1 new A.visible (%test%)
#2 main (%test%)
#3 _delayEntrypointInvocation.<anonymous closure> (isolate_patch.dart)
#4 _RawReceivePort._handleMessage (isolate_patch.dart)""",
"""
#0 main.<anonymous closure> (%test%)
#1 main (%test%)
<asynchronous suspension>""",
"""
#0 main.<anonymous closure> (%test%)
#1 visible (%test%)
#2 main (%test%)
<asynchronous suspension>""",
"""
#0 main.<anonymous closure> (%test%)
#1 main (%test%)
<asynchronous suspension>""",
"""
#0 main.<anonymous closure> (%test%)
#1 visibleClosure.visibleInner (%test%)
#2 visibleClosure (%test%)
#3 main (%test%)
<asynchronous suspension>""",
"""
#0 main.<anonymous closure> (%test%)
#1 invisibleClosure (%test%)
#2 main (%test%)
<asynchronous suspension>"""
];
// CURRENT EXPECTATIONS END

View file

@ -1,99 +1,49 @@
// 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.
// @dart = 2.9
//
// This test checks that --resolve-dwarf-paths outputs absolute and relative
// paths in DWARF information.
//
// VMOptions=--dwarf-stack-traces --resolve-dwarf-paths --save-debugging-info=$TEST_COMPILATION_DIR/debug.so
// OtherResources=use_save_debugging_info_flag_program.dart
// @dart=2.9
import "dart:async";
import "dart:io";
import 'package:expect/expect.dart';
import 'package:native_stack_traces/native_stack_traces.dart';
import 'package:path/path.dart' as path;
import 'package:path/path.dart' as p;
import 'use_flag_test_helper.dart';
main(List<String> args) async {
if (!isAOTRuntime) {
return; // Running in JIT: AOT binaries not available.
}
if (Platform.isAndroid) {
return; // SDK tree and dart_bootstrap not available on the test device.
return;
}
// These are the tools we need to be available to run on a given platform:
if (!await testExecutable(genSnapshot)) {
throw "Cannot run test as $genSnapshot not available";
}
if (!await testExecutable(dartPrecompiledRuntime)) {
throw "Cannot run test as $dartPrecompiledRuntime not available";
}
if (!File(platformDill).existsSync()) {
throw "Cannot run test as $platformDill does not exist";
final isDwarfStackTraces = StackTrace.current.toString().contains('*** ***');
if (!isDwarfStackTraces) {
return;
}
runTests(obfuscate: false);
runTests(obfuscate: true);
}
final dwarfPath =
p.join(Platform.environment['TEST_COMPILATION_DIR'], 'debug.so');
final dwarf = Dwarf.fromFile(dwarfPath);
void runTests({bool obfuscate}) async {
final pathSuffix = obfuscate ? 'obfuscated' : 'cleartext';
await withTempDir('dwarf-flag-test-$pathSuffix', (String tempDir) async {
final cwDir = path.dirname(Platform.script.toFilePath());
final script =
path.join(cwDir, 'use_save_debugging_info_flag_program.dart');
final scriptDill = path.join(tempDir, 'flag_program.dill');
// Compile script to Kernel IR.
await run(genKernel, <String>[
'--no-sound-null-safety',
'--aot',
'--platform=$platformDill',
'-o',
scriptDill,
script,
]);
final scriptDwarfSnapshot = path.join(tempDir, 'dwarf.so');
await run(genSnapshot, <String>[
if (obfuscate) ...[
'--obfuscate',
'--save-obfuscation-map=${path.join(tempDir, 'obfuscation.map')}',
],
'--no-sound-null-safety',
'--resolve-dwarf-paths',
'--dwarf-stack-traces-mode',
'--snapshot-kind=app-aot-elf',
'--elf=$scriptDwarfSnapshot',
scriptDill,
]);
// Run the resulting Dwarf-AOT compiled script.
final dwarfTrace = await runError(dartPrecompiledRuntime, <String>[
scriptDwarfSnapshot,
scriptDill,
]);
final tracePCOffsets = collectPCOffsets(dwarfTrace);
// Check that translating the DWARF stack trace (without internal frames)
// matches the symbolic stack trace.
final dwarf = Dwarf.fromFile(scriptDwarfSnapshot);
Expect.isNotNull(dwarf);
checkDwarfInfo(dwarf, tracePCOffsets);
});
final stack = StackTrace.current.toString();
print(stack);
final offsets = collectPCOffsets(stack.split('\n'));
print(offsets);
checkDwarfInfo(dwarf, offsets);
}
void checkDwarfInfo(Dwarf dwarf, Iterable<PCOffset> offsets) {
print(offsets);
final filenames = <String>{};
for (final offset in offsets) {
final callInfo = offset.callInfoFrom(dwarf);
final callInfo = offset.callInfoFrom(dwarf, includeInternalFrames: true);
Expect.isNotNull(callInfo);
Expect.isNotEmpty(callInfo);
for (final e in callInfo) {
@ -101,7 +51,7 @@ void checkDwarfInfo(Dwarf dwarf, Iterable<PCOffset> offsets) {
final entry = e as DartCallInfo;
var filename = entry.filename;
if (!filename.startsWith('/')) {
filename = path.join(sdkDir, filename);
filename = p.join(sdkDir, filename);
}
if (filenames.add(filename)) {
Expect.isTrue(
@ -114,4 +64,6 @@ void checkDwarfInfo(Dwarf dwarf, Iterable<PCOffset> offsets) {
print('- ${filename}');
}
Expect.isNotEmpty(filenames);
Expect.isNotEmpty(filenames
.where((p) => p.endsWith('use_resolve_dwarf_paths_flag_test.dart')));
}

View file

@ -141,14 +141,10 @@ dart_2/snapshot_depfile_test: SkipByDesign # Test needs to run from source
[ $compiler == dartkp ]
dart/await_type_check_with_dynamic_loading_test: SkipByDesign # Uses dart:mirrors.
dart/causal_stacks/async_throws_stack_no_causal_non_symbolic_test: SkipByDesign # --no-lazy... does nothing on precompiler.
dart/causal_stacks/async_throws_stack_no_causal_test: SkipByDesign # --no-lazy... does nothing on precompiler.
dart/finalizer/finalizer_isolate_groups_run_gc_test: SkipByDesign # Isolate.spawnUri is not supported in AOT.
dart/redirection_type_shuffling_test: SkipByDesign # Uses dart:mirrors.
dart/scavenger_abort_test: SkipSlow
dart/v8_snapshot_profile_writer_test: Pass, Slow # Can be slow due to re-invoking the precompiler.
dart_2/causal_stacks/async_throws_stack_no_causal_non_symbolic_test: SkipByDesign # --no-lazy... does nothing on precompiler.
dart_2/causal_stacks/async_throws_stack_no_causal_test: SkipByDesign # --no-lazy... does nothing on precompiler.
dart_2/redirection_type_shuffling_test: SkipByDesign # Uses dart:mirrors.
dart_2/scavenger_abort_test: SkipSlow
dart_2/v8_snapshot_profile_writer_test: Pass, Slow # Can be slow due to re-invoking the precompiler.
@ -386,10 +382,10 @@ dart/isolates/dart_api_create_lightweight_isolate_test: SkipByDesign # https://d
dart_2/isolates/dart_api_create_lightweight_isolate_test: SkipByDesign # https://dartbug.com/40579 Dart C API symbols not available.
[ $compiler == dartkp && $simulator ]
dart/causal_stacks/async_throws_stack_lazy_non_symbolic_test: Pass, Slow
dart/awaiter_stacks/async_throws_stack_lazy_non_symbolic_test: Pass, Slow
dart/isolates/fast_object_copy2_test*: Skip # Uses ffi which is not available on simulated architectures
dart/isolates/fast_object_copy_test*: SkipSlow
dart_2/causal_stacks/async_throws_stack_lazy_non_symbolic_test: Pass, Slow
dart_2/awaiter_stacks/async_throws_stack_lazy_non_symbolic_test: Pass, Slow
dart_2/isolates/fast_object_copy_test*: SkipSlow
[ $compiler == dartkp && ($builder_tag == tsan || $simulator) ]
@ -447,11 +443,11 @@ dart/run_appended_aot_snapshot_test: SkipByDesign # Tests the precompiled runtim
dart_2/run_appended_aot_snapshot_test: SkipByDesign # Tests the precompiled runtime.
[ $builder_tag == dwarf || $builder_tag == obfuscated ]
dart/causal_stacks/async_throws_stack_lazy_test: SkipByDesign # Asserts exact stacktrace output.
dart/causal_stacks/async_throws_stack_no_causal_test: SkipByDesign # Asserts exact stacktrace output.
dart/causal_stacks/flutter_regress_100441_test: SkipByDesign # Asserts exact stacktrace output.
dart/causal_stacks/sync_async_start_pkg_test_test: SkipByDesign # Asserts exact stacktrace output.
dart/causal_stacks/zone_callback_stack_traces_test: SkipByDesign # Asserts exact stacktrace output.
dart/awaiter_stacks/async_throws_stack_lazy_test: SkipByDesign # Asserts exact stacktrace output.
dart/awaiter_stacks/async_throws_stack_no_causal_test: SkipByDesign # Asserts exact stacktrace output.
dart/awaiter_stacks/flutter_regress_100441_test: SkipByDesign # Asserts exact stacktrace output.
dart/awaiter_stacks/sync_async_start_pkg_test_test: SkipByDesign # Asserts exact stacktrace output.
dart/awaiter_stacks/zone_callback_stack_traces_test: SkipByDesign # Asserts exact stacktrace output.
dart/checked_parameter_assert_assignable_stacktrace_test: SkipByDesign # Asserts exact stacktrace output.
dart/error_messages_in_null_checks_test: SkipByDesign # Relies symbol names in stack traces
dart/extension_names_test: SkipByDesign # Relies symbol names in stack traces
@ -461,11 +457,11 @@ dart/invisible_function_pragma_test: SkipByDesign # Relies symbol names in stack
dart/optimized_stacktrace_line_and_column_test: SkipByDesign # Relies symbol names in stack traces
dart/optimized_stacktrace_line_test: SkipByDesign # Relies symbol names in stack traces
dart/stacktrace_mixin_application_test: SkipByDesign # Relies symbol names in stack traces
dart_2/causal_stacks/async_throws_stack_lazy_test: SkipByDesign # Asserts exact stacktrace output.
dart_2/causal_stacks/async_throws_stack_no_causal_test: SkipByDesign # Asserts exact stacktrace output.
dart_2/causal_stacks/flutter_regress_100441_test: SkipByDesign # Asserts exact stacktrace output.
dart_2/causal_stacks/sync_async_start_pkg_test_test: SkipByDesign # Asserts exact stacktrace output.
dart_2/causal_stacks/zone_callback_stack_traces_test: SkipByDesign # Asserts exact stacktrace output.
dart_2/awaiter_stacks/async_throws_stack_lazy_test: SkipByDesign # Asserts exact stacktrace output.
dart_2/awaiter_stacks/async_throws_stack_no_causal_test: SkipByDesign # Asserts exact stacktrace output.
dart_2/awaiter_stacks/flutter_regress_100441_test: SkipByDesign # Asserts exact stacktrace output.
dart_2/awaiter_stacks/sync_async_start_pkg_test_test: SkipByDesign # Asserts exact stacktrace output.
dart_2/awaiter_stacks/zone_callback_stack_traces_test: SkipByDesign # Asserts exact stacktrace output.
dart_2/checked_parameter_assert_assignable_stacktrace_test: SkipByDesign # Asserts exact stacktrace output.
dart_2/error_messages_in_null_checks_test: SkipByDesign # Relies on uris / symbol names
dart_2/extension_names_test: SkipByDesign # Relies on uris / symbol names