Skip to content

Commit

Permalink
[pigeon] Fixes potential race condition caused by a ProxyApi construc…
Browse files Browse the repository at this point in the history
…tor message call being made in an async method (#8656)

Host api calls now declare a `Future` variable from `channel.send` first. Then it `await`s the future immedieately or inside of a async method.

Part of fixing webview_flutter_wkwebview issue: flutter/flutter#162437
  • Loading branch information
bparrishMines authored Feb 18, 2025
1 parent cb4fb13 commit eeecb3b
Show file tree
Hide file tree
Showing 18 changed files with 982 additions and 424 deletions.
5 changes: 5 additions & 0 deletions packages/pigeon/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 24.2.1

* [dart] Fixes potential race condition caused by a ProxyApi constructor message call being made in
an async method.

## 24.2.0

* Adjusts task queues to use a shared task queue for all methods in a single
Expand Down
11 changes: 8 additions & 3 deletions packages/pigeon/example/app/lib/src/messages.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,9 @@ class ExampleHostApi {
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(null);
final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(null) as List<Object?>?;
await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
Expand Down Expand Up @@ -155,8 +156,10 @@ class ExampleHostApi {
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[a, b]);
final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(<Object?>[a, b]) as List<Object?>?;
await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
Expand Down Expand Up @@ -184,8 +187,10 @@ class ExampleHostApi {
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[message]);
final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(<Object?>[message]) as List<Object?>?;
await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
Expand Down
23 changes: 20 additions & 3 deletions packages/pigeon/lib/src/dart/dart_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1115,6 +1115,7 @@ if (wrapped == null) {
required Iterable<Parameter> parameters,
required TypeDeclaration returnType,
required bool addSuffixVariable,
bool insideAsyncMethod = true,
}) {
String sendArgument = 'null';
if (parameters.isNotEmpty) {
Expand Down Expand Up @@ -1152,9 +1153,21 @@ if (wrapped == null) {
}
returnStatement = '$returnStatement;';

const String sendFutureVar = '${varNamePrefix}sendFuture';
indent.writeln(
'final Future<Object?> $sendFutureVar = ${varNamePrefix}channel.send($sendArgument);',
);

// If the message call is not made inside of an async method, this creates
// an anonymous function to handle the send future.
if (!insideAsyncMethod) {
indent.writeln('() async {');
indent.inc();
}

indent.format('''
final List<Object?>? ${varNamePrefix}replyList =
\t\tawait ${varNamePrefix}channel.send($sendArgument) as List<Object?>?;
\t\tawait $sendFutureVar as List<Object?>?;
if (${varNamePrefix}replyList == null) {
\tthrow _createConnectionError(${varNamePrefix}channelName);
} else if (${varNamePrefix}replyList.length > 1) {
Expand All @@ -1178,6 +1191,11 @@ if (${varNamePrefix}replyList == null) {
} else {
\t$returnStatement
}''');

if (!insideAsyncMethod) {
indent.dec();
indent.writeln('}();');
}
}

void _writeFlutterMethodMessageHandler(
Expand Down Expand Up @@ -1398,6 +1416,7 @@ if (${varNamePrefix}replyList == null) {
Indent(messageCallSink),
addSuffixVariable: false,
channelName: channelName,
insideAsyncMethod: false,
parameters: <Parameter>[
Parameter(
name: '${varNamePrefix}instanceIdentifier',
Expand Down Expand Up @@ -1426,9 +1445,7 @@ if (${varNamePrefix}replyList == null) {
cb.Code(
'final BinaryMessenger? ${varNamePrefix}binaryMessenger = ${binaryMessengerParameter.name};',
),
const cb.Code('() async {'),
cb.Code(messageCallSink.toString()),
const cb.Code('}();'),
]);
},
);
Expand Down
2 changes: 1 addition & 1 deletion packages/pigeon/lib/src/generator_tools.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import 'ast.dart';
/// The current version of pigeon.
///
/// This must match the version in pubspec.yaml.
const String pigeonVersion = '24.2.0';
const String pigeonVersion = '24.2.1';

/// Read all the content from [stdin] to a String.
String readStdin() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,12 @@ class BackgroundApi2Host {
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final Future<Object?> pigeonVar_sendFuture =
pigeonVar_channel.send(<Object?>[
<Object?>[x, y]
]);
final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(<Object?>[x, y]) as List<Object?>?;
await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
Expand Down
Loading

0 comments on commit eeecb3b

Please sign in to comment.