This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Fix FFI-based tonic layer to use proper C++ static_cast<>()s #47644
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Flutter makes use of C++ multiple inheritence in it's C++ classes that have corresponding Dart objects attached. An example is e.g.
When a C++ class has multiple base classes, the C++ compiler has the liberty to decide the order in which they get layed out in memory. (It doesn't necessarily follow declaration order, in fact it has a preference for having classes with
vtables before classes without vtables.)
Two casts to consider (with multiple inheritance in mind):
upcasts: Those are done by C++ automatically but can modify the actual address (i.e. pointer value)
downcasts: Those have to be done with
static_cast<>(), which can also modify the address (i.e. pointer value) - usingreinterpret_cast<>()is incorrect (as it doesn't modify the address)Now the Dart objects that refer to C++ objects have a native field in them. The value of that field is a
tonic::DartWrappable*. That means whenever we convert between the C++ object pointer (e.g.flutter::Canvas*) and the value of the native field (tonic::Wrappable*) the actual address / pointer may need modification.There were bugs in the C FFI based tonic layer: Pointer values coming from Dart (via C FFI) are
dart::Wrappable*and not pointers to subtypes.=> For methods we type the first parameter in tonic trampolines as
dart::Wrappable*andstatic_cast<Class*>()that value=> Similarly for arguments, the parameter has to be typed as
dart::Wrappable*andstatic_cast<Class*>()that valueHow did it ever work? Well it happens to be that the C++ compiler decided to layout
tonic::DartWrappablebeforefml::RefCountedThreadSafe, making thetonic::DartWrappable*and theflutter::Canvas*(and other classes) have the same pointer value.=> This worked due to implementation choice of C++ compiler.
=> This breaks immediately if one decided to add another base class (with virtual methods) to
RefCountedDartWrappable