-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Description
Dart SDK revision: ac3bc9f6351ac0a9c7f6b2dc3db735bd5b9fa2c5
Flutter engine base revision: df619c6a5237c2f82fd48806be2cfaf621024759
Environment: gLinux
Details
[!] Flutter (Channel main, 3.14.0-13.0.pre.60, on Debian GNU/Linux rodete 6.3.11-1rodete1-amd64, locale en_US.utf8)
• Flutter version 3.14.0-13.0.pre.60 on channel main at /[redacted]/dev/flutter
! Warning: `dart` on your path resolves to /usr/lib/google-dartlang/bin/dart, which is not inside your current Flutter SDK checkout at /[redacted]/dev/flutter. Consider adding
/[redacted]/dev/flutter/bin to the front of your path.
• Upstream repository [email protected]:flutter/flutter.git
• Framework revision 956999a4b9 (57 minutes ago), 2023-08-31 16:23:44 -0700
• Engine revision 10e2df60b0
• Dart version 3.2.0 (build 3.2.0-126.0.dev)
• DevTools version 2.27.0
• If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades.
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
• Android SDK at /[redacted]/Android/Sdk
• Platform android-31, build-tools 30.0.3
• Java binary at: /opt/android-studio-with-blaze-2020.3/jre/bin/java
• Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7249189)
• All Android licenses accepted.
[✓] Chrome - develop for the web
• Chrome at google-chrome
[✓] Linux toolchain - develop for Linux desktop
• Debian clang version 14.0.6
• cmake version 3.25.1
• ninja version 1.11.1
• pkg-config version 1.8.1
[✓] Android Studio (version 3.5)
• Android Studio at /[redacted]/src/android-studio
• Flutter plugin version 43.0.1
• Dart plugin version 191.8593
• Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)
[✓] Android Studio (version 2020.3)
• Android Studio at /opt/android-studio-with-blaze-2020.3
• Flutter plugin version 65.2.1
• Dart plugin version 203.8452
• Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7249189)
[✓] VS Code (version 1.78.0)
• VS Code at /usr/share/code
• Flutter extension version 3.70.0
[✓] Connected device (2 available)
• Linux (desktop) • linux • linux-x64 • Debian GNU/Linux rodete 6.3.11-1rodete1-amd64
• Chrome (web) • chrome • web-javascript • Google Chrome 116.0.5845.140
[✓] Network resources
• All expected network resources are available.
! Doctor found issues in 1 category.
When the Dart VM parses a flag, if the flag is not registered, then the name is captured by Flag but is never disposed, and eventually leaked.
Following is the leakage reported by ASAN:
=================================================================
==132854==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 27 byte(s) in 1 object(s) allocated from:
#0 0x557aef9e2fdd in operator new[](unsigned long) ../llvm_build/tools/clang/stage2-bins/runtimes/runtimes-x86_64-unknown-linux-gnu-bins/../llvm_build/tools/clang/stage2-bins/runtimes/runtimes-x86_64-unknown-linux-gnu-bins/compiler-rt/lib/asan/asan_new_delete.cpp:98:3
#1 0x557af52f0573 in dart::Flags::Parse(char const*) /[redacted]/dev/engine/src/out/host_debug_unopt/../../third_party/dart/runtime/vm/flags.cc:400:22
#2 0x557af52f09d8 in dart::Flags::ProcessCommandLineFlags(int, char const**) /[redacted]/dev/engine/src/out/host_debug_unopt/../../third_party/dart/runtime/vm/flags.cc:447:5
#3 0x557af5e2a301 in flutter::DartVM::DartVM(std::_LIBCPP_ABI_NAMESPACE::shared_ptr<flutter::DartVMData const> const&, std::_LIBCPP_ABI_NAMESPACE::shared_ptr<flutter::IsolateNameServer>) /[redacted]/dev/engine/src/out/host_debug_unopt/../../flutter/runtime/dart_vm.cc:430:23
#4 0x557af5e28bb0 in flutter::DartVM::Create(flutter::Settings const&, fml::RefPtr<flutter::DartSnapshot const>, fml::RefPtr<flutter::DartSnapshot const>, std::_LIBCPP_ABI_NAMESPACE::shared_ptr<flutter::IsolateNameServer>) /[redacted]/dev/engine/src/out/host_debug_unopt/../../flutter/runtime/dart_vm.cc:274:11
#5 0x557af5e387e4 in flutter::DartVMRef::Create(flutter::Settings const&, fml::RefPtr<flutter::DartSnapshot const>, fml::RefPtr<flutter::DartSnapshot const>) /[redacted]/dev/engine/src/out/host_debug_unopt/../../flutter/runtime/dart_vm_lifecycle.cc:78:13
#6 0x557af5f1d29f in flutter::Shell::InferVmInitDataFromSettings(flutter::Settings&) /[redacted]/dev/engine/src/out/host_debug_unopt/../../flutter/shell/common/shell.cc:154:13
#7 0x557aefc3ec04 in flutter::(anonymous namespace)::RuntimeControllerContext::Create(flutter::Settings, flutter::TaskRunners const&, flutter::RuntimeDelegate&) /[redacted]/dev/engine/src/out/host_debug_unopt/../../flutter/lib/ui/window/platform_configuration_unittests.cc:109:35
#8 0x557aefc3fe48 in flutter::testing::PlatformConfigurationTest_DuplicateRenderCallsAreIgnored_Test::TestBody() /[redacted]/dev/engine/src/out/host_debug_unopt/../../flutter/lib/ui/window/platform_configuration_unittests.cc:544:7
#9 0x557af829386f in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /[redacted]/dev/engine/src/out/host_debug_unopt/../../third_party/googletest/googletest/src/gtest.cc:2631:10
#10 0x557af8270920 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /[redacted]/dev/engine/src/out/host_debug_unopt/../../third_party/googletest/googletest/src/gtest.cc:2686:12
#11 0x557af8242dcd in testing::Test::Run() /[redacted]/dev/engine/src/out/host_debug_unopt/../../third_party/googletest/googletest/src/gtest.cc:2706:5
#12 0x557af8244090 in testing::TestInfo::Run() /[redacted]/dev/engine/src/out/host_debug_unopt/../../third_party/googletest/googletest/src/gtest.cc:2885:11
#13 0x557af8245200 in testing::TestSuite::Run() /[redacted]/dev/engine/src/out/host_debug_unopt/../../third_party/googletest/googletest/src/gtest.cc:3044:30
#14 0x557af825d6cc in testing::internal::UnitTestImpl::RunAllTests() /[redacted]/dev/engine/src/out/host_debug_unopt/../../third_party/googletest/googletest/src/gtest.cc:5913:44
#15 0x557af829c5af in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /[redacted]/dev/engine/src/out/host_debug_unopt/../../third_party/googletest/googletest/src/gtest.cc:2631:10
#16 0x557af8274e6d in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /[redacted]/dev/engine/src/out/host_debug_unopt/../../third_party/googletest/googletest/src/gtest.cc:2686:12
#17 0x557af825cb34 in testing::UnitTest::Run() /[redacted]/dev/engine/src/out/host_debug_unopt/../../third_party/googletest/googletest/src/gtest.cc:5482:10
#18 0x557af01821f0 in RUN_ALL_TESTS() /[redacted]/dev/engine/src/out/host_debug_unopt/../../third_party/googletest/googletest/include/gtest/gtest.h:2497:46
#19 0x557af0181ded in main /[redacted]/dev/engine/src/out/host_debug_unopt/../../flutter/testing/run_all_unittests.cc:71:17
#20 0x7fd90fbc36c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
The leaked string is disable-service-auth-codes\0, which Flutter has been assigning but I suspect Dart has recently removed. Removing this flag from Flutter's code also eliminates leakage warnings.
Analysis
The leakage message leads us to the following code in flags.cc:
void Flags::Parse(const char* option) {
// ...
Flag* flag = Flags::Lookup(name);
if (flag == nullptr) {
// Collect unrecognized flags.
char* new_flag = new char[name_len + 1]; // <-- HERE
strncpy(new_flag, option, name_len);
new_flag[name_len] = '\0';
Flags::Register_bool(nullptr, new_flag, true, nullptr);
} else {
// Only set values for recognized flags, skip collected
// unrecognized flags.
if (!flag->IsUnrecognized()) {
if (!SetFlagFromString(flag, argument)) {
OS::PrintErr("Ignoring flag: %s is an invalid value for flag %s\n",
argument, name);
}
}
}The new_flag is allocated here, passed into Register_bool, and never deleted. Register_bool stores the string in a Flag, but Flag doesn't deallocate this string either, probably because normally Flag receives a constant string.
FYI, we can't immediately delete new_flag after Register_bool, apparently since it's used in Flag later.
Reproduction
The leakage can be reproduced by running the unit tests introduced in my PR when compiled with --asan. (I understand that having to compile the entire Flutter engine for it might be too much, but honestly I think the analysis above should be convincing enough that a repro is not needed. Let me know if a more isolated repro is wanted.)
- Set up the Flutter engine development environment
- Check out my PR:
git checkout -b dkwingsmt-enforce-rendering-rule main
git pull [email protected]:dkwingsmt/engine.git enforce-rendering-rule
git checkout 151ed777ca244f187588945f9b2f29012ca8869d
- Compile.
gn --asan --unoptimized
ninja -C $ENGINE_SRC/out/host_debug_unopt
- Run test:
../out/host_debug_unopt/exe.unstripped/ui_unittests --gtest_filter="*RenderCalls*"