[ddc] Fix unsound await expressions

Some expressions have a static type that can lead to a possible
soundness issue when awaited. For those expressions an additional
runtime check is performed.

Issue: https://github.com/dart-lang/sdk/issues/49396
Fixes: https://github.com/dart-lang/sdk/issues/50602
Change-Id: Ief25fbe8c38330cca0c17be4d411780a20ab87a0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/274729
Reviewed-by: Mark Zhou <markzipan@google.com>
Commit-Queue: Nicholas Shahan <nshahan@google.com>
This commit is contained in:
Nicholas Shahan 2022-12-12 19:43:55 +00:00 committed by Commit Queue
parent 3a1cc9faf6
commit 0b3533aa95
2 changed files with 25 additions and 2 deletions

View file

@ -6879,8 +6879,20 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
}
@override
js_ast.Expression visitAwaitExpression(AwaitExpression node) =>
js_ast.Yield(_visitExpression(node.operand));
js_ast.Expression visitAwaitExpression(AwaitExpression node) {
var expression = _visitExpression(node.operand);
var type = node.runtimeCheckType;
if (type != null) {
// When an expected runtime type is present there is a possible soundness
// issue with the static types. The type of the await expression must be
// checked at runtime to ensure soundness.
var expectedType = _emitType(type);
var asyncLibrary = emitLibraryName(_coreTypes.asyncLibrary);
expression = js.call('#.awaitWithTypeCheck(#, #)',
[asyncLibrary, expectedType, expression]);
}
return js_ast.Yield(expression);
}
@override
js_ast.Expression visitFunctionExpression(FunctionExpression node) {

View file

@ -129,6 +129,17 @@ _async<T>(Function() initGenerator) {
return asyncFuture;
}
/// Checks that the value being awaited is a Future of the expected type and
/// if not the value is wrapped in a new Future.
///
/// Calls to the method are generated from the compiler when it detects a type
/// check is required on the expression in an await.
///
/// Closes a soundness hole where null could leak from an awaited Future.
@JSExportName('awaitWithTypeCheck')
_awaitWithTypeCheck<T>(Object? value) =>
value is T ? value : _Future.value(value);
@patch
class _AsyncRun {
@patch