Skip to content

Commit 216e464

Browse files
[pigeon] Fix handling of null class args in C++ (flutter#6881)
The code generated for Windows (C++) crashes when `null` is passed for a nullable, class-type parameter to a Pigeon method. This fixes that generation, and adds an integration test covering this case since it was missing from the list of types where we echo a `null` in integration tests to catch this kind of issue. Fixes flutter#149174
1 parent 14722b7 commit 216e464

File tree

7 files changed

+143
-110
lines changed

7 files changed

+143
-110
lines changed

packages/pigeon/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 20.0.1
2+
3+
* [cpp] Fixes handling of null class arguments.
4+
15
## 20.0.0
26

37
* Moves all codec logic to single custom codec per file.

packages/pigeon/lib/cpp_generator.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -1529,7 +1529,7 @@ if (!$encodableArgName.IsNull()) {
15291529
}''');
15301530
} else {
15311531
indent.writeln(
1532-
'const auto* $argName = &(${_classReferenceFromEncodableValue(hostType, encodableArgName)});');
1532+
'const auto* $argName = $encodableArgName.IsNull() ? nullptr : &(${_classReferenceFromEncodableValue(hostType, encodableArgName)});');
15331533
}
15341534
} else {
15351535
// Non-nullable arguments are either passed by value or reference, but the

packages/pigeon/lib/generator_tools.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import 'ast.dart';
1313
/// The current version of pigeon.
1414
///
1515
/// This must match the version in pubspec.yaml.
16-
const String pigeonVersion = '20.0.0';
16+
const String pigeonVersion = '20.0.1';
1717

1818
/// Prefix for all local variables in methods.
1919
///

packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart

+9
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,15 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) {
983983
expect(echoEnum, sentEnum);
984984
});
985985

986+
testWidgets('null classes serialize and deserialize correctly',
987+
(WidgetTester _) async {
988+
final HostIntegrationCoreApi api = HostIntegrationCoreApi();
989+
990+
final AllNullableTypes? echoObject = await api.echoAllNullableTypes(null);
991+
992+
expect(echoObject, isNull);
993+
});
994+
986995
testWidgets('optional nullable parameter', (WidgetTester _) async {
987996
final HostIntegrationCoreApi api = HostIntegrationCoreApi();
988997

packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp

+126-106
Original file line numberDiff line numberDiff line change
@@ -2261,9 +2261,11 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger,
22612261
const auto& args = std::get<EncodableList>(message);
22622262
const auto& encodable_everything_arg = args.at(0);
22632263
const auto* everything_arg =
2264-
&(std::any_cast<const AllNullableTypes&>(
2265-
std::get<CustomEncodableValue>(
2266-
encodable_everything_arg)));
2264+
encodable_everything_arg.IsNull()
2265+
? nullptr
2266+
: &(std::any_cast<const AllNullableTypes&>(
2267+
std::get<CustomEncodableValue>(
2268+
encodable_everything_arg)));
22672269
ErrorOr<std::optional<AllNullableTypes>> output =
22682270
api->EchoAllNullableTypes(everything_arg);
22692271
if (output.has_error()) {
@@ -2295,35 +2297,38 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger,
22952297
prepended_suffix,
22962298
&GetCodec());
22972299
if (api != nullptr) {
2298-
channel.SetMessageHandler(
2299-
[api](const EncodableValue& message,
2300-
const flutter::MessageReply<EncodableValue>& reply) {
2301-
try {
2302-
const auto& args = std::get<EncodableList>(message);
2303-
const auto& encodable_everything_arg = args.at(0);
2304-
const auto* everything_arg =
2305-
&(std::any_cast<const AllNullableTypesWithoutRecursion&>(
2306-
std::get<CustomEncodableValue>(
2307-
encodable_everything_arg)));
2308-
ErrorOr<std::optional<AllNullableTypesWithoutRecursion>> output =
2309-
api->EchoAllNullableTypesWithoutRecursion(everything_arg);
2310-
if (output.has_error()) {
2311-
reply(WrapError(output.error()));
2312-
return;
2313-
}
2314-
EncodableList wrapped;
2315-
auto output_optional = std::move(output).TakeValue();
2316-
if (output_optional) {
2317-
wrapped.push_back(
2318-
CustomEncodableValue(std::move(output_optional).value()));
2319-
} else {
2320-
wrapped.push_back(EncodableValue());
2321-
}
2322-
reply(EncodableValue(std::move(wrapped)));
2323-
} catch (const std::exception& exception) {
2324-
reply(WrapError(exception.what()));
2325-
}
2326-
});
2300+
channel.SetMessageHandler([api](
2301+
const EncodableValue& message,
2302+
const flutter::MessageReply<EncodableValue>&
2303+
reply) {
2304+
try {
2305+
const auto& args = std::get<EncodableList>(message);
2306+
const auto& encodable_everything_arg = args.at(0);
2307+
const auto* everything_arg =
2308+
encodable_everything_arg.IsNull()
2309+
? nullptr
2310+
: &(std::any_cast<const AllNullableTypesWithoutRecursion&>(
2311+
std::get<CustomEncodableValue>(
2312+
encodable_everything_arg)));
2313+
ErrorOr<std::optional<AllNullableTypesWithoutRecursion>> output =
2314+
api->EchoAllNullableTypesWithoutRecursion(everything_arg);
2315+
if (output.has_error()) {
2316+
reply(WrapError(output.error()));
2317+
return;
2318+
}
2319+
EncodableList wrapped;
2320+
auto output_optional = std::move(output).TakeValue();
2321+
if (output_optional) {
2322+
wrapped.push_back(
2323+
CustomEncodableValue(std::move(output_optional).value()));
2324+
} else {
2325+
wrapped.push_back(EncodableValue());
2326+
}
2327+
reply(EncodableValue(std::move(wrapped)));
2328+
} catch (const std::exception& exception) {
2329+
reply(WrapError(exception.what()));
2330+
}
2331+
});
23272332
} else {
23282333
channel.SetMessageHandler(nullptr);
23292334
}
@@ -3459,9 +3464,11 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger,
34593464
const auto& args = std::get<EncodableList>(message);
34603465
const auto& encodable_everything_arg = args.at(0);
34613466
const auto* everything_arg =
3462-
&(std::any_cast<const AllNullableTypes&>(
3463-
std::get<CustomEncodableValue>(
3464-
encodable_everything_arg)));
3467+
encodable_everything_arg.IsNull()
3468+
? nullptr
3469+
: &(std::any_cast<const AllNullableTypes&>(
3470+
std::get<CustomEncodableValue>(
3471+
encodable_everything_arg)));
34653472
api->EchoAsyncNullableAllNullableTypes(
34663473
everything_arg,
34673474
[reply](ErrorOr<std::optional<AllNullableTypes>>&& output) {
@@ -3495,39 +3502,41 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger,
34953502
prepended_suffix,
34963503
&GetCodec());
34973504
if (api != nullptr) {
3498-
channel.SetMessageHandler(
3499-
[api](const EncodableValue& message,
3500-
const flutter::MessageReply<EncodableValue>& reply) {
3501-
try {
3502-
const auto& args = std::get<EncodableList>(message);
3503-
const auto& encodable_everything_arg = args.at(0);
3504-
const auto* everything_arg =
3505-
&(std::any_cast<const AllNullableTypesWithoutRecursion&>(
3506-
std::get<CustomEncodableValue>(
3507-
encodable_everything_arg)));
3508-
api->EchoAsyncNullableAllNullableTypesWithoutRecursion(
3509-
everything_arg,
3510-
[reply](
3511-
ErrorOr<std::optional<AllNullableTypesWithoutRecursion>>&&
3505+
channel.SetMessageHandler([api](
3506+
const EncodableValue& message,
3507+
const flutter::MessageReply<EncodableValue>&
3508+
reply) {
3509+
try {
3510+
const auto& args = std::get<EncodableList>(message);
3511+
const auto& encodable_everything_arg = args.at(0);
3512+
const auto* everything_arg =
3513+
encodable_everything_arg.IsNull()
3514+
? nullptr
3515+
: &(std::any_cast<const AllNullableTypesWithoutRecursion&>(
3516+
std::get<CustomEncodableValue>(
3517+
encodable_everything_arg)));
3518+
api->EchoAsyncNullableAllNullableTypesWithoutRecursion(
3519+
everything_arg,
3520+
[reply](ErrorOr<std::optional<AllNullableTypesWithoutRecursion>>&&
35123521
output) {
3513-
if (output.has_error()) {
3514-
reply(WrapError(output.error()));
3515-
return;
3516-
}
3517-
EncodableList wrapped;
3518-
auto output_optional = std::move(output).TakeValue();
3519-
if (output_optional) {
3520-
wrapped.push_back(CustomEncodableValue(
3521-
std::move(output_optional).value()));
3522-
} else {
3523-
wrapped.push_back(EncodableValue());
3524-
}
3525-
reply(EncodableValue(std::move(wrapped)));
3526-
});
3527-
} catch (const std::exception& exception) {
3528-
reply(WrapError(exception.what()));
3529-
}
3530-
});
3522+
if (output.has_error()) {
3523+
reply(WrapError(output.error()));
3524+
return;
3525+
}
3526+
EncodableList wrapped;
3527+
auto output_optional = std::move(output).TakeValue();
3528+
if (output_optional) {
3529+
wrapped.push_back(
3530+
CustomEncodableValue(std::move(output_optional).value()));
3531+
} else {
3532+
wrapped.push_back(EncodableValue());
3533+
}
3534+
reply(EncodableValue(std::move(wrapped)));
3535+
});
3536+
} catch (const std::exception& exception) {
3537+
reply(WrapError(exception.what()));
3538+
}
3539+
});
35313540
} else {
35323541
channel.SetMessageHandler(nullptr);
35333542
}
@@ -4057,9 +4066,11 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger,
40574066
const auto& args = std::get<EncodableList>(message);
40584067
const auto& encodable_everything_arg = args.at(0);
40594068
const auto* everything_arg =
4060-
&(std::any_cast<const AllNullableTypes&>(
4061-
std::get<CustomEncodableValue>(
4062-
encodable_everything_arg)));
4069+
encodable_everything_arg.IsNull()
4070+
? nullptr
4071+
: &(std::any_cast<const AllNullableTypes&>(
4072+
std::get<CustomEncodableValue>(
4073+
encodable_everything_arg)));
40634074
api->CallFlutterEchoAllNullableTypes(
40644075
everything_arg,
40654076
[reply](ErrorOr<std::optional<AllNullableTypes>>&& output) {
@@ -4142,39 +4153,41 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger,
41424153
prepended_suffix,
41434154
&GetCodec());
41444155
if (api != nullptr) {
4145-
channel.SetMessageHandler(
4146-
[api](const EncodableValue& message,
4147-
const flutter::MessageReply<EncodableValue>& reply) {
4148-
try {
4149-
const auto& args = std::get<EncodableList>(message);
4150-
const auto& encodable_everything_arg = args.at(0);
4151-
const auto* everything_arg =
4152-
&(std::any_cast<const AllNullableTypesWithoutRecursion&>(
4153-
std::get<CustomEncodableValue>(
4154-
encodable_everything_arg)));
4155-
api->CallFlutterEchoAllNullableTypesWithoutRecursion(
4156-
everything_arg,
4157-
[reply](
4158-
ErrorOr<std::optional<AllNullableTypesWithoutRecursion>>&&
4156+
channel.SetMessageHandler([api](
4157+
const EncodableValue& message,
4158+
const flutter::MessageReply<EncodableValue>&
4159+
reply) {
4160+
try {
4161+
const auto& args = std::get<EncodableList>(message);
4162+
const auto& encodable_everything_arg = args.at(0);
4163+
const auto* everything_arg =
4164+
encodable_everything_arg.IsNull()
4165+
? nullptr
4166+
: &(std::any_cast<const AllNullableTypesWithoutRecursion&>(
4167+
std::get<CustomEncodableValue>(
4168+
encodable_everything_arg)));
4169+
api->CallFlutterEchoAllNullableTypesWithoutRecursion(
4170+
everything_arg,
4171+
[reply](ErrorOr<std::optional<AllNullableTypesWithoutRecursion>>&&
41594172
output) {
4160-
if (output.has_error()) {
4161-
reply(WrapError(output.error()));
4162-
return;
4163-
}
4164-
EncodableList wrapped;
4165-
auto output_optional = std::move(output).TakeValue();
4166-
if (output_optional) {
4167-
wrapped.push_back(CustomEncodableValue(
4168-
std::move(output_optional).value()));
4169-
} else {
4170-
wrapped.push_back(EncodableValue());
4171-
}
4172-
reply(EncodableValue(std::move(wrapped)));
4173-
});
4174-
} catch (const std::exception& exception) {
4175-
reply(WrapError(exception.what()));
4176-
}
4177-
});
4173+
if (output.has_error()) {
4174+
reply(WrapError(output.error()));
4175+
return;
4176+
}
4177+
EncodableList wrapped;
4178+
auto output_optional = std::move(output).TakeValue();
4179+
if (output_optional) {
4180+
wrapped.push_back(
4181+
CustomEncodableValue(std::move(output_optional).value()));
4182+
} else {
4183+
wrapped.push_back(EncodableValue());
4184+
}
4185+
reply(EncodableValue(std::move(wrapped)));
4186+
});
4187+
} catch (const std::exception& exception) {
4188+
reply(WrapError(exception.what()));
4189+
}
4190+
});
41784191
} else {
41794192
channel.SetMessageHandler(nullptr);
41804193
}
@@ -5108,8 +5121,12 @@ void FlutterIntegrationCoreApi::EchoAllNullableTypes(
51085121
std::get<std::string>(list_return_value->at(1)),
51095122
list_return_value->at(2)));
51105123
} else {
5111-
const auto* return_value = &(std::any_cast<const AllNullableTypes&>(
5112-
std::get<CustomEncodableValue>(list_return_value->at(0))));
5124+
const auto* return_value =
5125+
list_return_value->at(0).IsNull()
5126+
? nullptr
5127+
: &(std::any_cast<const AllNullableTypes&>(
5128+
std::get<CustomEncodableValue>(
5129+
list_return_value->at(0))));
51135130
on_success(return_value);
51145131
}
51155132
} else {
@@ -5191,8 +5208,11 @@ void FlutterIntegrationCoreApi::EchoAllNullableTypesWithoutRecursion(
51915208
list_return_value->at(2)));
51925209
} else {
51935210
const auto* return_value =
5194-
&(std::any_cast<const AllNullableTypesWithoutRecursion&>(
5195-
std::get<CustomEncodableValue>(list_return_value->at(0))));
5211+
list_return_value->at(0).IsNull()
5212+
? nullptr
5213+
: &(std::any_cast<const AllNullableTypesWithoutRecursion&>(
5214+
std::get<CustomEncodableValue>(
5215+
list_return_value->at(0))));
51965216
on_success(return_value);
51975217
}
51985218
} else {

packages/pigeon/pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: pigeon
22
description: Code generator tool to make communication between Flutter and the host platform type-safe and easier.
33
repository: https://github.com/flutter/packages/tree/main/packages/pigeon
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+pigeon%22
5-
version: 20.0.0 # This must match the version in lib/generator_tools.dart
5+
version: 20.0.1 # This must match the version in lib/generator_tools.dart
66

77
environment:
88
sdk: ^3.2.0

packages/pigeon/test/cpp_generator_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -1194,7 +1194,7 @@ void main() {
11941194
expect(
11951195
code,
11961196
contains(
1197-
'const auto* an_object_arg = &(std::any_cast<const ParameterObject&>(std::get<CustomEncodableValue>(encodable_an_object_arg)));'));
1197+
'const auto* an_object_arg = encodable_an_object_arg.IsNull() ? nullptr : &(std::any_cast<const ParameterObject&>(std::get<CustomEncodableValue>(encodable_an_object_arg)));'));
11981198
// "Object" requires no extraction at all since it has to use
11991199
// EncodableValue directly.
12001200
expect(

0 commit comments

Comments
 (0)