diff --git a/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc b/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc index 0b07e6c3a9f..4e1014ac9ad 100644 --- a/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc +++ b/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc @@ -60,24 +60,23 @@ class SurfaceMock : public Surface { }; fml::RefPtr GetThreadMergerFromPlatformThread( - bool merged = false) { + fml::Thread* rasterizer_thread = nullptr) { // Assume the current thread is the platform thread. fml::MessageLoop::EnsureInitializedForCurrentThread(); auto platform_queue_id = fml::MessageLoop::GetCurrentTaskQueueId(); - if (merged) { + if (!rasterizer_thread) { return fml::MakeRefCounted(platform_queue_id, platform_queue_id); } - auto rasterizer_thread = new fml::Thread("rasterizer"); auto rasterizer_queue_id = rasterizer_thread->GetTaskRunner()->GetTaskQueueId(); return fml::MakeRefCounted(platform_queue_id, rasterizer_queue_id); } -fml::RefPtr GetThreadMergerFromRasterThread() { - auto platform_thread = new fml::Thread("rasterizer"); +fml::RefPtr GetThreadMergerFromRasterThread( + fml::Thread* platform_thread) { auto platform_queue_id = platform_thread->GetTaskRunner()->GetTaskQueueId(); // Assume the current thread is the raster thread. @@ -94,7 +93,9 @@ TEST(AndroidExternalViewEmbedder, GetCurrentCanvases) { auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware); auto embedder = std::make_unique( android_context, jni_mock, nullptr); - auto raster_thread_merger = GetThreadMergerFromPlatformThread(); + fml::Thread rasterizer_thread("rasterizer"); + auto raster_thread_merger = + GetThreadMergerFromPlatformThread(&rasterizer_thread); EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()); embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0, @@ -117,7 +118,9 @@ TEST(AndroidExternalViewEmbedder, GetCurrentCanvases__CompositeOrder) { auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware); auto embedder = std::make_unique( android_context, jni_mock, nullptr); - auto raster_thread_merger = GetThreadMergerFromPlatformThread(); + fml::Thread rasterizer_thread("rasterizer"); + auto raster_thread_merger = + GetThreadMergerFromPlatformThread(&rasterizer_thread); EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()); embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0, @@ -169,7 +172,9 @@ TEST(AndroidExternalViewEmbedder, RasterizerRunsOnPlatformThread) { auto embedder = std::make_unique( android_context, jni_mock, nullptr); - auto raster_thread_merger = GetThreadMergerFromPlatformThread(); + fml::Thread rasterizer_thread("rasterizer"); + auto raster_thread_merger = + GetThreadMergerFromPlatformThread(&rasterizer_thread); ASSERT_FALSE(raster_thread_merger->IsMerged()); EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()); @@ -201,7 +206,9 @@ TEST(AndroidExternalViewEmbedder, RasterizerRunsOnRasterizerThread) { auto embedder = std::make_unique( android_context, jni_mock, nullptr); - auto raster_thread_merger = GetThreadMergerFromPlatformThread(); + fml::Thread rasterizer_thread("rasterizer"); + auto raster_thread_merger = + GetThreadMergerFromPlatformThread(&rasterizer_thread); ASSERT_FALSE(raster_thread_merger->IsMerged()); PostPrerollResult result = embedder->PostPrerollAction(raster_thread_merger); @@ -219,7 +226,9 @@ TEST(AndroidExternalViewEmbedder, PlatformViewRect) { auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware); auto embedder = std::make_unique( android_context, jni_mock, nullptr); - auto raster_thread_merger = GetThreadMergerFromPlatformThread(); + fml::Thread rasterizer_thread("rasterizer"); + auto raster_thread_merger = + GetThreadMergerFromPlatformThread(&rasterizer_thread); EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()); embedder->BeginFrame(SkISize::Make(100, 100), nullptr, 1.5, @@ -245,7 +254,9 @@ TEST(AndroidExternalViewEmbedder, PlatformViewRect__ChangedParams) { auto android_context = AndroidContext(AndroidRenderingAPI::kSoftware); auto embedder = std::make_unique( android_context, jni_mock, nullptr); - auto raster_thread_merger = GetThreadMergerFromPlatformThread(); + fml::Thread rasterizer_thread("rasterizer"); + auto raster_thread_merger = + GetThreadMergerFromPlatformThread(&rasterizer_thread); EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()); embedder->BeginFrame(SkISize::Make(100, 100), nullptr, 1.5, @@ -318,8 +329,7 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame) { auto embedder = std::make_unique( *android_context, jni_mock, surface_factory); - auto raster_thread_merger = - GetThreadMergerFromPlatformThread(/*merged=*/true); + auto raster_thread_merger = GetThreadMergerFromPlatformThread(); // ------------------ First frame ------------------ // { @@ -511,8 +521,7 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame__overlayComposition) { auto embedder = std::make_unique( *android_context, jni_mock, surface_factory); - auto raster_thread_merger = - GetThreadMergerFromPlatformThread(/*merged=*/true); + auto raster_thread_merger = GetThreadMergerFromPlatformThread(); EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()); embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger); @@ -613,8 +622,7 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame__platformViewWithoutAnyOverlay) { auto embedder = std::make_unique( *android_context, jni_mock, surface_factory); - auto raster_thread_merger = - GetThreadMergerFromPlatformThread(/*merged=*/true); + auto raster_thread_merger = GetThreadMergerFromPlatformThread(); EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()); embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger); @@ -655,7 +663,8 @@ TEST(AndroidExternalViewEmbedder, DoesNotCallJNIPlatformThreadOnlyMethods) { // While on the raster thread, don't make JNI calls as these methods can only // run on the platform thread. - auto raster_thread_merger = GetThreadMergerFromRasterThread(); + fml::Thread platform_thread("platform"); + auto raster_thread_merger = GetThreadMergerFromRasterThread(&platform_thread); EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()).Times(0); embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0, @@ -699,7 +708,9 @@ TEST(AndroidExternalViewEmbedder, DestroyOverlayLayersOnSizeChange) { auto embedder = std::make_unique( *android_context, jni_mock, surface_factory); - auto raster_thread_merger = GetThreadMergerFromPlatformThread(); + fml::Thread rasterizer_thread("rasterizer"); + auto raster_thread_merger = + GetThreadMergerFromPlatformThread(&rasterizer_thread); // ------------------ First frame ------------------ // { @@ -784,7 +795,9 @@ TEST(AndroidExternalViewEmbedder, DoesNotDestroyOverlayLayersOnSizeChange) { // ------------------ First frame ------------------ // { - auto raster_thread_merger = GetThreadMergerFromPlatformThread(); + fml::Thread rasterizer_thread("rasterizer"); + auto raster_thread_merger = + GetThreadMergerFromPlatformThread(&rasterizer_thread); EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()); embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger); @@ -827,8 +840,9 @@ TEST(AndroidExternalViewEmbedder, DoesNotDestroyOverlayLayersOnSizeChange) { EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces()).Times(0); EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()).Times(0); + fml::Thread platform_thread("platform"); embedder->BeginFrame(SkISize::Make(30, 40), nullptr, 1.0, - GetThreadMergerFromRasterThread()); + GetThreadMergerFromRasterThread(&platform_thread)); } TEST(AndroidExternalViewEmbedder, SupportsDynamicThreadMerging) { @@ -845,7 +859,8 @@ TEST(AndroidExternalViewEmbedder, DisableThreadMerger) { auto embedder = std::make_unique( android_context, jni_mock, nullptr); - auto raster_thread_merger = GetThreadMergerFromRasterThread(); + fml::Thread platform_thread("platform"); + auto raster_thread_merger = GetThreadMergerFromRasterThread(&platform_thread); ASSERT_FALSE(raster_thread_merger->IsMerged()); // The shell may disable the thread merger during `OnPlatformViewDestroyed`. diff --git a/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests_gl.cc b/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests_gl.cc index b731923fa02..c79c6d20562 100644 --- a/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests_gl.cc +++ b/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests_gl.cc @@ -3537,7 +3537,9 @@ TEST_F(EmbedderTest, CreateInvalidBackingstoreOpenGLTexture) { backing_store_out->open_gl.texture.target = 0; backing_store_out->open_gl.texture.name = 0; backing_store_out->open_gl.texture.format = 0; - backing_store_out->open_gl.texture.user_data = new TestCollectOnce(); + static TestCollectOnce collect_once_user_data; + collect_once_user_data = {}; + backing_store_out->open_gl.texture.user_data = &collect_once_user_data; backing_store_out->open_gl.texture.destruction_callback = [](void* user_data) { reinterpret_cast(user_data)->Collect(); @@ -3597,8 +3599,10 @@ TEST_F(EmbedderTest, CreateInvalidBackingstoreOpenGLFramebuffer) { backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; backing_store_out->open_gl.framebuffer.target = 0; backing_store_out->open_gl.framebuffer.name = 0; + static TestCollectOnce collect_once_user_data; + collect_once_user_data = {}; backing_store_out->open_gl.framebuffer.user_data = - new TestCollectOnce(); + &collect_once_user_data; backing_store_out->open_gl.framebuffer.destruction_callback = [](void* user_data) { reinterpret_cast(user_data)->Collect(); diff --git a/engine/src/flutter/shell/platform/linux/fl_event_channel_test.cc b/engine/src/flutter/shell/platform/linux/fl_event_channel_test.cc index cff868b0d6b..d40ad3276ea 100644 --- a/engine/src/flutter/shell/platform/linux/fl_event_channel_test.cc +++ b/engine/src/flutter/shell/platform/linux/fl_event_channel_test.cc @@ -42,8 +42,9 @@ static void listen_channel(FlBinaryMessenger* messenger, FlValue* args) { g_autoptr(FlValue) invoke_args = fl_value_new_list(); fl_value_append_take(invoke_args, fl_value_new_string("test/standard-event")); fl_value_append_take(invoke_args, fl_value_new_string("listen")); - fl_value_append(invoke_args, - args != nullptr ? fl_value_ref(args) : fl_value_new_null()); + g_autoptr(FlValue) value = + args != nullptr ? fl_value_ref(args) : fl_value_new_null(); + fl_value_append(invoke_args, value); fl_method_channel_invoke_method(channel, "InvokeMethod", invoke_args, nullptr, nullptr, nullptr); } @@ -58,8 +59,9 @@ static void cancel_channel(FlBinaryMessenger* messenger, FlValue* args) { g_autoptr(FlValue) invoke_args = fl_value_new_list(); fl_value_append_take(invoke_args, fl_value_new_string("test/standard-event")); fl_value_append_take(invoke_args, fl_value_new_string("cancel")); - fl_value_append_take( - invoke_args, args != nullptr ? fl_value_ref(args) : fl_value_new_null()); + g_autoptr(FlValue) value = + args != nullptr ? fl_value_ref(args) : fl_value_new_null(); + fl_value_append(invoke_args, value); fl_method_channel_invoke_method(channel, "InvokeMethod", invoke_args, nullptr, nullptr, nullptr); } diff --git a/engine/src/flutter/testing/lsan_suppressions.txt b/engine/src/flutter/testing/lsan_suppressions.txt index d6f0be9a4ff..03eda3d326e 100644 --- a/engine/src/flutter/testing/lsan_suppressions.txt +++ b/engine/src/flutter/testing/lsan_suppressions.txt @@ -40,3 +40,26 @@ leak:flutter::Engine::Run(flutter::RunConfiguration) leak:txt::FontCollection::CreateMinikinFontFamily leak:CGFontCreateFontsWithURL leak:txt::GetDefaultFontFamily + +# The RefCounted DebugChecks tests intentionally fail to wrap and manage heap +# allocated objects. +leak:RefCountedTest_DebugChecks_Test::TestBody + +# Objects allocated by this mock API are intentionally not collected and are +# instead marked as released in order to explicitly assert double free attempts +# and allow some tests to inspect contents. +leak:*flutter/shell/platform/linux/testing/mock_engine.cc + +# TODO(bdero): Fix FL leaks: https://github.com/flutter/flutter/issues/90155 +leak:*flutter/shell/platform/linux/fl_keyboard_manager_test.cc* +leak:*flutter/shell/platform/linux/fl_key_channel_responder_test.cc* +leak:*flutter/shell/platform/linux/fl_basic_message_channel_test.cc* +leak:fl_message_codec_decode_message + +# TODO(bdero): https://github.com/flutter/flutter/issues/90156 +# Unfortunately, realloc calls originating from g_realloc effectively obscure +# the trace of the original allocation. Deeper investigation is required to +# identify the original allocation source for these. +# At the time of writing, this only amounts to 4 allocations totaling 512 bytes +# worth of leaks. +leak:g_realloc diff --git a/engine/src/flutter/testing/sanitizer_suppressions.sh b/engine/src/flutter/testing/sanitizer_suppressions.sh index 4634cb9a76f..1da0c1b636e 100755 --- a/engine/src/flutter/testing/sanitizer_suppressions.sh +++ b/engine/src/flutter/testing/sanitizer_suppressions.sh @@ -22,6 +22,5 @@ UBSAN_SUPPRESSIONS_FILE="${TESTING_DIRECTORY}/ubsan_suppressions.txt" export UBSAN_OPTIONS="suppressions=${UBSAN_SUPPRESSIONS_FILE}" echo "Using Undefined Behavior suppressions in ${UBSAN_SUPPRESSIONS_FILE}" - -export ASAN_OPTIONS="symbolize=1:detect_leaks=0" +export ASAN_OPTIONS="symbolize=1:detect_leaks=1" export ASAN_SYMBOLIZER_PATH="${BUILDTOOLS_DIRECTORY}/clang/bin/llvm-symbolizer"