Use g_signal_connect_object in the Linux embedder#188241
Conversation
Replace g_signal_connect_swapped with g_signal_connect_object (with G_CONNECT_SWAPPED) in cases where the signal emitter can outlive the user-data object. g_signal_connect_object automatically disconnects the handler when the user-data object is finalized, which lets us drop the manually tracked signal-connection IDs and the manual disconnect code in the dispose functions.
|
It looks like this pull request may not have tests. Please make sure to add tests or get an explicit test exemption before merging. If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix? Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. If you believe this PR qualifies for a test exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!). The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group. |
There was a problem hiding this comment.
Code Review
This pull request refactors the Linux shell platform code to use g_signal_connect_object instead of g_signal_connect_swapped for signal handling, removing manual signal disconnection logic during object disposal. However, the review feedback highlights that this change introduces critical regressions and potential crashes across multiple files, including fl_window_monitor.cc, fl_view_monitor.cc, fl_keyboard_manager.cc, fl_view.cc, and fl_window_state_monitor.cc. Because g_signal_connect_object disconnects handlers during finalization rather than disposal, signals emitted after disposal can invoke callbacks on partially disposed objects. The reviewer recommends retaining explicit signal disconnection in the dispose methods using g_signal_handlers_disconnect_by_data to prevent these issues.
I am having trouble creating individual review comments. Click here to see my feedback.
engine/src/flutter/shell/platform/linux/fl_window_monitor.cc (83-85)
Removing g_signal_handlers_disconnect_by_data(self->window, self) introduces a critical regression.
The Issue
g_signal_connect_object automatically disconnects signal handlers when the target object (self) is finalized, not when it is disposed.
During fl_window_monitor_dispose, g_clear_object(&self->window) is called, which releases the reference to the window. If this is the last reference, the window is destroyed, emitting the "destroy" signal. Because self is only in its dispose phase (and not yet finalized), the weak reference used by g_signal_connect_object is still active, so destroy_cb(self) will be invoked.
Inside destroy_cb, it will call self->on_destroy(self) on a partially disposed FlWindowMonitor object, which can lead to crashes, use-after-free, or infinite recursion.
Solution
We must keep the explicit disconnection of signals in dispose before clearing the window object. Since we are using g_signal_connect_object, we can still avoid tracking individual connection IDs by using g_signal_handlers_disconnect_by_data:
static void fl_window_monitor_dispose(GObject* object) {
FlWindowMonitor* self = FL_WINDOW_MONITOR(object);
g_signal_handlers_disconnect_by_data(self->window, self);
g_clear_object(&self->window);
G_OBJECT_CLASS(fl_window_monitor_parent_class)->dispose(object);
}References
- Check for potential regressions: Look for changes that might break existing functionality or introduce unexpected behavior in related areas. (link)
engine/src/flutter/shell/platform/linux/fl_view_monitor.cc (35-37)
Removing g_signal_handlers_disconnect_by_data(self->view, self) introduces a potential crash/regression.
The Issue
g_signal_connect_object automatically disconnects signal handlers when the target object (self) is finalized, not when it is disposed.
During fl_view_monitor_dispose, g_clear_object(&self->view) is called. If the view is destroyed, or if any pending "first-frame" signals are emitted after FlViewMonitor is disposed but before it is finalized, first_frame_cb(self) will be invoked on a partially disposed FlViewMonitor object (where self->view is already NULL), leading to a crash.
Solution
We should keep the explicit disconnection of signals in dispose before clearing the view object. We can still avoid tracking individual connection IDs by using g_signal_handlers_disconnect_by_data:
static void fl_view_monitor_dispose(GObject* object) {
FlViewMonitor* self = FL_VIEW_MONITOR(object);
g_signal_handlers_disconnect_by_data(self->view, self);
g_clear_object(&self->view);
G_OBJECT_CLASS(fl_view_monitor_parent_class)->dispose(object);
}References
- Check for potential regressions: Look for changes that might break existing functionality or introduce unexpected behavior in related areas. (link)
engine/src/flutter/shell/platform/linux/fl_keyboard_manager.cc (321-324)
Removing the manual signal disconnection here introduces a potential crash/regression.
The Issue
g_signal_connect_object automatically disconnects signal handlers when the target object (self) is finalized, not when it is disposed.
If the "keys-changed" signal is emitted on self->keymap after FlKeyboardManager is disposed but before it is finalized, keymap_keys_changed_cb(self) will be invoked on a partially disposed FlKeyboardManager object (where self->derived_layout and other fields are already NULL), leading to a crash.
Solution
We should keep the explicit disconnection of signals in dispose. However, we can still achieve the goal of removing the manually tracked connection ID (keymap_keys_changed_cb_id) by using g_signal_handlers_disconnect_by_data:
static void fl_keyboard_manager_dispose(GObject* object) {
FlKeyboardManager* self = FL_KEYBOARD_MANAGER(object);
g_clear_object(&self->key_embedder_responder);
g_clear_object(&self->key_channel_responder);
g_clear_object(&self->derived_layout);
if (self->keymap != nullptr) {
g_signal_handlers_disconnect_by_data(self->keymap, self);
}
g_clear_object(&self->cancellable);
G_OBJECT_CLASS(fl_keyboard_manager_parent_class)->dispose(object);
}References
- Check for potential regressions: Look for changes that might break existing functionality or introduce unexpected behavior in related areas. (link)
engine/src/flutter/shell/platform/linux/fl_view.cc (606-611)
Removing the manual signal disconnection for the cursor handler here introduces a potential crash/regression.
The Issue
g_signal_connect_object automatically disconnects signal handlers when the target object (self) is finalized, not when it is disposed.
If the "cursor-changed" signal is emitted on the mouse cursor handler after FlView is disposed but before it is finalized, cursor_changed_cb(self) will be invoked on a partially disposed FlView object, leading to a crash.
Solution
We should keep the explicit disconnection of signals in dispose. We can still achieve the goal of removing the manually tracked connection ID (cursor_changed_cb_id) by using g_signal_handlers_disconnect_by_data:
if (self->engine != nullptr) {
FlMouseCursorHandler* handler =
fl_engine_get_mouse_cursor_handler(self->engine);
g_signal_handlers_disconnect_by_data(handler, self);
// Release the view ID from the engine.
fl_engine_remove_view(self->engine, self->view_id, nullptr, nullptr,
nullptr);
}References
- Check for potential regressions: Look for changes that might break existing functionality or introduce unexpected behavior in related areas. (link)
engine/src/flutter/shell/platform/linux/fl_view.cc (618-627)
Removing the manual signal disconnections for the engine signals here introduces a potential crash/regression.
The Issue
g_signal_connect_object automatically disconnects signal handlers when the target object (self) is finalized, not when it is disposed.
If "on-pre-engine-restart" or "update-semantics" signals are emitted on self->engine after FlView is disposed but before it is finalized, the callbacks will be invoked on a partially disposed FlView object, leading to a crash.
Solution
We should keep the explicit disconnection of signals in dispose. We can still achieve the goal of removing the manually tracked connection IDs (on_pre_engine_restart_cb_id and update_semantics_cb_id) by using g_signal_handlers_disconnect_by_data:
if (self->engine != nullptr) {
g_signal_handlers_disconnect_by_data(self->engine, self);
}References
- Check for potential regressions: Look for changes that might break existing functionality or introduce unexpected behavior in related areas. (link)
engine/src/flutter/shell/platform/linux/fl_window_state_monitor.cc (89-92)
Removing the manual signal disconnection here introduces a potential crash/regression.
The Issue
g_signal_connect_object automatically disconnects signal handlers when the target object (self) is finalized, not when it is disposed.
If the "window-state-event" signal is emitted on self->window after FlWindowStateMonitor is disposed but before it is finalized, window_state_event_cb(self) will be invoked on a partially disposed FlWindowStateMonitor object (where self->messenger is already NULL), leading to a crash.
Solution
We should keep the explicit disconnection of signals in dispose. We can still achieve the goal of removing the manually tracked connection ID (window_state_event_cb_id) by using g_signal_handlers_disconnect_by_data:
static void fl_window_state_monitor_dispose(GObject* object) {
FlWindowStateMonitor* self = FL_WINDOW_STATE_MONITOR(object);
g_signal_handlers_disconnect_by_data(self->window, self);
g_clear_object(&self->messenger);
G_OBJECT_CLASS(fl_window_state_monitor_parent_class)->dispose(object);
}References
- Check for potential regressions: Look for changes that might break existing functionality or introduce unexpected behavior in related areas. (link)
flutter/flutter@e228771...87224e0 2026-06-23 engine-flutter-autoroll@skia.org Roll Dart SDK from 5cae7f9ada62 to 3a66ea7b9aaa (1 revision) (flutter/flutter#188379) 2026-06-23 engine-flutter-autoroll@skia.org Roll Dart SDK from 1e6c246bb73a to 5cae7f9ada62 (2 revisions) (flutter/flutter#188370) 2026-06-23 engine-flutter-autoroll@skia.org Roll Skia from 766f21ae61dc to ffac3e91fbc7 (24 revisions) (flutter/flutter#188366) 2026-06-23 737941+loic-sharma@users.noreply.github.com [Windows] Add public API to post task to platform thread (flutter/flutter#187365) 2026-06-23 engine-flutter-autoroll@skia.org Roll Dart SDK from 7ab0179ce4d4 to 1e6c246bb73a (1 revision) (flutter/flutter#188354) 2026-06-23 robert.ancell@canonical.com Fix byte/character offset confusion in FlAccessibleTextField (flutter/flutter#188138) 2026-06-22 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from Lm76V7lvxVA0r1De5... to RymJjIj7dd5vQ3Cnh... (flutter/flutter#188353) 2026-06-22 137456488+flutter-pub-roller-bot@users.noreply.github.com Roll pub packages (flutter/flutter#188355) 2026-06-22 154381524+flutteractionsbot@users.noreply.github.com Sync CHANGELOG.md from stable (flutter/flutter#188331) 2026-06-22 engine-flutter-autoroll@skia.org Roll Skia from 5fbb9bbd889c to 766f21ae61dc (2 revisions) (flutter/flutter#188184) 2026-06-22 49699333+dependabot[bot]@users.noreply.github.com Bump actions/checkout from 6.0.3 to 7.0.0 in the all-github-actions group (flutter/flutter#188350) 2026-06-22 robert.ancell@canonical.com Use g_signal_connect_object in the Linux embedder (flutter/flutter#188241) 2026-06-22 robert.ancell@canonical.com Disconnect from parent window signal when view is destroyed (flutter/flutter#185521) 2026-06-22 rmacnak@google.com Remove many absolute paths from build commands. (flutter/flutter#187765) 2026-06-22 haiderqadir.hq@gmail.com Fix spelling mistake in documentation (wether → whether) (flutter/flutter#186141) 2026-06-22 engine-flutter-autoroll@skia.org Roll Dart SDK from a748c4b15399 to 7ab0179ce4d4 (2 revisions) (flutter/flutter#188332) 2026-06-22 robert.ancell@canonical.com [Linux] Move compositor shader into its own GObject (flutter/flutter#188144) 2026-06-22 bkonyi@google.com Add agent skills for orchestrating cherry-picks to stable and beta channels (flutter/flutter#187860) 2026-06-22 engine-flutter-autoroll@skia.org Roll Packages from c516c92 to cd5194a (1 revision) (flutter/flutter#188312) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC stuartmorgan@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Replace g_signal_connect_swapped with g_signal_connect_object (with G_CONNECT_SWAPPED) in cases where the signal emitter can outlive the user-data object. g_signal_connect_object automatically disconnects the handler when the user-data object is finalized, which lets us drop the manually tracked signal-connection IDs and the manual disconnect code in the dispose functions.
Replace g_signal_connect_swapped with g_signal_connect_object (with G_CONNECT_SWAPPED) in cases where the signal emitter can outlive the user-data object. g_signal_connect_object automatically disconnects the handler when the user-data object is finalized, which lets us drop the manually tracked signal-connection IDs and the manual disconnect code in the dispose functions.