Skip to content

[Linux] Realized software renderer loses its task runner during GTK disposal #196545

Description

@saitatter

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.PresentLayersAfterRealizedDestroy

The 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

  1. added
    c: crashStack traces logged to the console
    engineflutter/engine related. See also e: labels.
    platform-linuxBuilding on or for Linux specifically
    team-linuxOwned by the Linux platform team
    on Nov 13, 2026
  2. mbcorona commented on Nov 13, 2026

    @mbcorona
    Member

    Hi @saitatter , thanks for the report and for raising a PR.
    Routing to the linux team for evaluation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    a: desktopRunning on desktopc: crashStack traces logged to the consoleengineflutter/engine related. See also e: labels.platform-linuxBuilding on or for Linux specificallyteam-linuxOwned by the Linux platform team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions