Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PlatformInterface._instanceToken needs reworking due to an upcoming dart language change #109339

Closed
stereotype441 opened this issue Aug 10, 2022 · 4 comments · Fixed by flutter/plugins#6411
Assignees
Labels
P2 Important issues not at the top of the work list package flutter/packages repository. See also p: labels.

Comments

@stereotype441
Copy link
Contributor

stereotype441 commented Aug 10, 2022

The dart language team will soon be changing the behavior of the language so that an invocation of a private class members won't get dispatched to a noSuchMethod method in another library; instead an exception will be thrown. This is a necessary prerequisite to allowing promotion of private fields (dart-lang/language#2020). It also closes an important privacy loophole in the language, by ensuring that the user can see all the possible behaviors of a private member invocation without having to look outside of the library.

This has an important consequence for PlatformInterface (from the plugin_platform_interface package), which insists that it be subclassed by clients via extends rather than implements, and detects the difference by reading from the private field _instanceToken and checking whether the expected value was returned. Today, that technique works some of the time (it relies on the implementing class having an implementation of noSuchMethod that completes without throwing an exception), but after the upcoming language change it will always throw a yet-to-be-defined exception.

I believe we should change PlatformInterface._instanceToken to use an expando (similar to what was done in #109238), so that PlatformInterface will be able to reliably detect whether it is subclassed by extends or implements, both before and after the upcoming language change.

In the process we'll also need to update several brittle tests that rely on the invocation of _instanceToken being dispatched to the standard Object.noSuchMethod method, and thus expect a NoSuchMethodError to be thrown. Changing PlatformInterface._instanceToken to use an expando will prevent the NoSuchMethodError from occurring, and instead PlatformInterface._verify will throw an AssertionError. These tests need to be updated so that they don't care what particular kind of exception is thrown. The tests I've found that require fixing are in the following repos:

To avoid breakages, I'll submit PRs to these repos before landing the change to PlatformInterface.

@stereotype441 stereotype441 self-assigned this Aug 10, 2022
@goderbauer
Copy link
Member

I believe you're talking about this class here, which is from the plugin_platform_interface package and not part of the Flutter framework itself:

https://github.com/flutter/plugins/blob/395dc14b27e0ba1bb02a65168b510e55fa7fc09d/packages/plugin_platform_interface/lib/plugin_platform_interface.dart#L42

I don't actually have too much context about how this class is used. Maybe @stuartmorgan or someone from his team can help out?

@stereotype441
Copy link
Contributor Author

I believe you're talking about this class here, which is from the plugin_platform_interface package and not part of the Flutter framework itself:

https://github.com/flutter/plugins/blob/395dc14b27e0ba1bb02a65168b510e55fa7fc09d/packages/plugin_platform_interface/lib/plugin_platform_interface.dart#L42

You're right, thanks. Edited the issue to clarify.

@stuartmorgan
Copy link
Contributor

which insists that it be subclassed by clients via extends rather than implements, and detects the difference by reading from the private field _instanceToken and checking whether the expected value was returned. Today, that technique works some of the time (it relies on the implementing class having an implementation of noSuchMethod that completes without throwing an exception), but after the upcoming language change it will always throw a yet-to-be-defined exception.

Summarizing from discussion elsewhere since I was confused about this: the key functionality of verify*, which is completing without an exception only when extends is used, works all of the time, and will continue to work even after the change. The part that only sometimes works and will never work in the future is actually throwing an AssertionError rather than some other error (like NoSuchMethodError as explained above).

So it's already the case that the behavior doesn't match the documentation, and the difference will only ever affect tests since the whole point here is that this is to prevent people from shipping code that uses implements (which it will accomplish regardless of the specific Error type).

But we should match the documented behavior (and provide the better error message that our own assertion error contains), so changing to an Expando seems reasonable to me.

@stuartmorgan stuartmorgan added the P2 Important issues not at the top of the work list label Aug 16, 2022
stereotype441 added a commit to stereotype441/flutterfire that referenced this issue Aug 16, 2022
Currently, in some circumstances where a subclasses of
`PlatformInterface` erroneously uses `implements` rather than
`extends`, a `NoSuchMethodError` will be thrown (in spite of the
documentation at
https://pub.dev/documentation/plugin_platform_interface/latest/plugin_platform_interface/PlatformInterface/verify.html
claiming that `AssertionError` will be thrown).

After flutter/flutter#109339 is fixed, the
correct type of exception will be thrown.  To avoid a test breakage in
`platform_interface_firebase_core_test.dart` when the fix happens, we
need to modify the test so that it doesn't care what kind of exception
is thrown.
stereotype441 added a commit to stereotype441/flutter-geocoding that referenced this issue Aug 16, 2022
Currently, in some circumstances where a subclasses of
`PlatformInterface` erroneously uses `implements` rather than
`extends`, a `NoSuchMethodError` will be thrown (in spite of the
documentation at
https://pub.dev/documentation/plugin_platform_interface/latest/plugin_platform_interface/PlatformInterface/verify.html
claiming that `AssertionError` will be thrown).

After flutter/flutter#109339 is fixed, the
correct type of exception will be thrown.  To avoid a test breakage in
`geocoding_platform_interface_test.dart` when the fix happens, we need
to modify the test so that it doesn't care what kind of exception is
thrown.
stereotype441 added a commit to stereotype441/flutter-geolocator that referenced this issue Aug 16, 2022
Currently, in some circumstances where a subclasses of
`PlatformInterface` erroneously uses `implements` rather than
`extends`, a `NoSuchMethodError` will be thrown (in spite of the
documentation at
https://pub.dev/documentation/plugin_platform_interface/latest/plugin_platform_interface/PlatformInterface/verify.html
claiming that `AssertionError` will be thrown).

After flutter/flutter#109339 is fixed, the
correct type of exception will be thrown.  To avoid a test breakage in
`geolocator_platform_interface_test.dart` when the fix happens, we
need to modify the test so that it doesn't care what kind of exception
is thrown.
stereotype441 added a commit to stereotype441/plugins that referenced this issue Aug 16, 2022
Currently, in some circumstances where a subclasses of
`PlatformInterface` erroneously uses `implements` rather than
`extends`, a `NoSuchMethodError` will be thrown (in spite of the
documentation at
https://pub.dev/documentation/plugin_platform_interface/latest/plugin_platform_interface/PlatformInterface/verify.html
claiming that `AssertionError` will be thrown).

After flutter/flutter#109339 is fixed, the
correct type of exception will be thrown.  To avoid tests breakages
when the fix happens, we need to modify these tests so that they don't
care what kind of exception is thrown.
stuartmorgan pushed a commit to flutter/plugins that referenced this issue Aug 17, 2022
Currently, in some circumstances where a subclasses of
`PlatformInterface` erroneously uses `implements` rather than
`extends`, a `NoSuchMethodError` will be thrown (in spite of the
documentation at
https://pub.dev/documentation/plugin_platform_interface/latest/plugin_platform_interface/PlatformInterface/verify.html
claiming that `AssertionError` will be thrown).

After flutter/flutter#109339 is fixed, the
correct type of exception will be thrown.  To avoid tests breakages
when the fix happens, we need to modify these tests so that they don't
care what kind of exception is thrown.
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this issue Aug 17, 2022
mvanbeusekom pushed a commit to Baseflow/flutter-geolocator that referenced this issue Aug 18, 2022
Currently, in some circumstances where a subclasses of
`PlatformInterface` erroneously uses `implements` rather than
`extends`, a `NoSuchMethodError` will be thrown (in spite of the
documentation at
https://pub.dev/documentation/plugin_platform_interface/latest/plugin_platform_interface/PlatformInterface/verify.html
claiming that `AssertionError` will be thrown).

After flutter/flutter#109339 is fixed, the
correct type of exception will be thrown.  To avoid a test breakage in
`geolocator_platform_interface_test.dart` when the fix happens, we
need to modify the test so that it doesn't care what kind of exception
is thrown.
russellwheatley pushed a commit to firebase/flutterfire that referenced this issue Aug 22, 2022
camsim99 pushed a commit to camsim99/plugins that referenced this issue Aug 23, 2022
Currently, in some circumstances where a subclasses of
`PlatformInterface` erroneously uses `implements` rather than
`extends`, a `NoSuchMethodError` will be thrown (in spite of the
documentation at
https://pub.dev/documentation/plugin_platform_interface/latest/plugin_platform_interface/PlatformInterface/verify.html
claiming that `AssertionError` will be thrown).

After flutter/flutter#109339 is fixed, the
correct type of exception will be thrown.  To avoid tests breakages
when the fix happens, we need to modify these tests so that they don't
care what kind of exception is thrown.
mvanbeusekom pushed a commit to Baseflow/flutter-geocoding that referenced this issue Aug 25, 2022
Currently, in some circumstances where a subclasses of
`PlatformInterface` erroneously uses `implements` rather than
`extends`, a `NoSuchMethodError` will be thrown (in spite of the
documentation at
https://pub.dev/documentation/plugin_platform_interface/latest/plugin_platform_interface/PlatformInterface/verify.html
claiming that `AssertionError` will be thrown).

After flutter/flutter#109339 is fixed, the
correct type of exception will be thrown.  To avoid a test breakage in
`geocoding_platform_interface_test.dart` when the fix happens, we need
to modify the test so that it doesn't care what kind of exception is
thrown.
moisefeelin pushed a commit to feelinproject/plugins that referenced this issue Aug 26, 2022
Currently, in some circumstances where a subclasses of
`PlatformInterface` erroneously uses `implements` rather than
`extends`, a `NoSuchMethodError` will be thrown (in spite of the
documentation at
https://pub.dev/documentation/plugin_platform_interface/latest/plugin_platform_interface/PlatformInterface/verify.html
claiming that `AssertionError` will be thrown).

After flutter/flutter#109339 is fixed, the
correct type of exception will be thrown.  To avoid tests breakages
when the fix happens, we need to modify these tests so that they don't
care what kind of exception is thrown.
stereotype441 added a commit to stereotype441/plugins that referenced this issue Sep 12, 2022
This change replaces `PlatformInterface._instanceToken` (an instance
field that points from a `PlatformInterface` to its corresponding
token) with an expando that maps from `PlatformInterface` to `Object`.
There is no change to the public API, and no change to the behavior of
users' production code.

This change ensures that if a customer tries to implement
`PlatformInterface` using `implements` rather than `extends`, the code
in `PlatformInterface._verify` won't try to access the private
`_instanceToken` field in `PlatformInterface`.  This is important
because an upcoming change to the dart language is going to cause such
accesses to throw exceptions rather than deferring to `noSuchMethod`
(see dart-lang/language#2020 for details).

Fixes flutter/flutter#109339.
stereotype441 added a commit to flutter/plugins that referenced this issue Sep 15, 2022
… to an expando. (#6411)

This change replaces `PlatformInterface._instanceToken` (an instance
field that points from a `PlatformInterface` to its corresponding
token) with an expando that maps from `PlatformInterface` to `Object`.
There is no change to the public API, and no change to the behavior of
users' production code.

This change ensures that if a customer tries to implement
`PlatformInterface` using `implements` rather than `extends`, the code
in `PlatformInterface._verify` won't try to access the private
`_instanceToken` field in `PlatformInterface`.  This is important
because an upcoming change to the dart language is going to cause such
accesses to throw exceptions rather than deferring to `noSuchMethod`
(see dart-lang/language#2020 for details).

Fixes flutter/flutter#109339.
mvanbeusekom added a commit to Baseflow/flutter-permission-handler that referenced this issue Sep 20, 2022
mvanbeusekom added a commit to Baseflow/flutter-permission-handler that referenced this issue Sep 20, 2022
@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 29, 2022
adam-harwood pushed a commit to adam-harwood/flutter_plugins that referenced this issue Nov 3, 2022
… to an expando. (flutter#6411)

This change replaces `PlatformInterface._instanceToken` (an instance
field that points from a `PlatformInterface` to its corresponding
token) with an expando that maps from `PlatformInterface` to `Object`.
There is no change to the public API, and no change to the behavior of
users' production code.

This change ensures that if a customer tries to implement
`PlatformInterface` using `implements` rather than `extends`, the code
in `PlatformInterface._verify` won't try to access the private
`_instanceToken` field in `PlatformInterface`.  This is important
because an upcoming change to the dart language is going to cause such
accesses to throw exceptions rather than deferring to `noSuchMethod`
(see dart-lang/language#2020 for details).

Fixes flutter/flutter#109339.
mauricioluz pushed a commit to mauricioluz/plugins that referenced this issue Jan 26, 2023
… to an expando. (flutter#6411)

This change replaces `PlatformInterface._instanceToken` (an instance
field that points from a `PlatformInterface` to its corresponding
token) with an expando that maps from `PlatformInterface` to `Object`.
There is no change to the public API, and no change to the behavior of
users' production code.

This change ensures that if a customer tries to implement
`PlatformInterface` using `implements` rather than `extends`, the code
in `PlatformInterface._verify` won't try to access the private
`_instanceToken` field in `PlatformInterface`.  This is important
because an upcoming change to the dart language is going to cause such
accesses to throw exceptions rather than deferring to `noSuchMethod`
(see dart-lang/language#2020 for details).

Fixes flutter/flutter#109339.
engine-flutter-autoroll pushed a commit to engine-flutter-autoroll/packages that referenced this issue Feb 22, 2023
… to an expando. (flutter#6411)

This change replaces `PlatformInterface._instanceToken` (an instance
field that points from a `PlatformInterface` to its corresponding
token) with an expando that maps from `PlatformInterface` to `Object`.
There is no change to the public API, and no change to the behavior of
users' production code.

This change ensures that if a customer tries to implement
`PlatformInterface` using `implements` rather than `extends`, the code
in `PlatformInterface._verify` won't try to access the private
`_instanceToken` field in `PlatformInterface`.  This is important
because an upcoming change to the dart language is going to cause such
accesses to throw exceptions rather than deferring to `noSuchMethod`
(see dart-lang/language#2020 for details).

Fixes flutter/flutter#109339.
@flutter-triage-bot flutter-triage-bot bot added the package flutter/packages repository. See also p: labels. label Jul 5, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
P2 Important issues not at the top of the work list package flutter/packages repository. See also p: labels.
Projects
None yet
3 participants