Repository navigation
Description
Problem
A realized FlViewRendererSoftware can still receive a frame while a caller holds a strong reference after GTK destroys the widget. Its dispose() clears task_runner, but leaves compositor alive until finalize(). Consequently present_layers() passes its compositor guard and calls fl_task_runner_stop_wait(nullptr), causing SIGSEGV in g_cond_signal().
Reproduced in the Linux engine unit tests at master 215858ff8a1e51fb5481c7c7cc4c6d4be54b8ae0, Ubuntu 24.04, GTK 3.24.41, X11/Xvfb. No application plugins are involved.
Reproduction
In fl_view_renderer_software_test.cc, include testing/fl_test_gtk_logs.h alongside the existing Linux testing headers and add:
TEST_F(FlViewRendererSoftwareTest, PresentLayersAfterRealizedDestroy) {
StartEngine();
fl_engine_get_embedder_api(engine)->ScheduleFrame =
MOCK_ENGINE_PROC(ScheduleFrame, ([](auto engine) { return kSuccess; }));
g_autoptr(FlViewRendererSoftware) renderer =
fl_view_renderer_software_new(engine, FALSE);
g_object_ref_sink(renderer);
GtkWidget* window = gtk_offscreen_window_new();
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(renderer));
gtk_widget_show_all(window);
ASSERT_TRUE(gtk_widget_get_realized(GTK_WIDGET(renderer)));
fl_gtk_widget_destroy(GTK_WIDGET(renderer));
fl_gtk_widget_destroy(window);
flutter::testing::fl_reset_received_gtk_log_levels();
fl_view_renderer_present_layers(FL_VIEW_RENDERER(renderer), nullptr, 0);
EXPECT_FALSE(
flutter::testing::fl_has_received_gtk_log_level(G_LOG_LEVEL_CRITICAL));
while (g_main_context_iteration(nullptr, FALSE)) {
}
}After the standard engine dependency setup:
./engine/src/flutter/tools/gn --runtime-mode=debug --unoptimized --no-rbe
ninja -C engine/src/out/host_debug_unopt flutter_linux_unittests
dbus-run-session -- xvfb-run -a engine/src/out/host_debug_unopt/flutter_linux_unittests \
--gtest_filter=FlViewRendererSoftwareTest.PresentLayersAfterRealizedDestroyThe existing PresentLayersAfterDestroy test does not realize the widget, so compositor remains null and frame presentation returns before exercising this path.
Actual result
SIGSEGV in g_cond_signal
fl_task_runner_stop_wait(self=0x0)
fl_view_renderer_software_present_layers(..., layers_count=0)
fl_view_renderer_present_layers(...)
FlViewRendererSoftwareTest_PresentLayersAfterRealizedDestroy_Test::TestBody()
Expected result and verification
Frame state used during presentation should remain available until the last renderer reference is released. Moving task_runner and frame_mutex cleanup to finalize() makes the regression pass 100 consecutive repetitions; the complete Linux unit suite passes 862 tests.
Related: #188659 / #188702 and the open #193533. The latter addresses OpenGL/Subsurface renderer lifetime; this report isolates the software renderer, whose file is not changed by that PR.
Prepared with AI assistance; the failing baseline, symbolized stack, fixed regression and complete Linux suite were executed locally.
Activity
mbcorona commentedon Nov 13, 2026
Hi @saitatter , thanks for the report and for raising a PR.
Routing to the linux team for evaluation.