Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 12f48f7

Browse files
authored
Allow for whitelisted flags to be passed to the Dart VM (#9148)
* Allow for whitelisted flags to be passed to the Dart VM Fixed part of flutter/flutter#32176
1 parent b304dab commit 12f48f7

File tree

3 files changed

+88
-5
lines changed

3 files changed

+88
-5
lines changed

shell/common/shell_unittests.cc

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
#include <future>
99
#include <memory>
1010

11+
#include "flutter/fml/command_line.h"
1112
#include "flutter/fml/make_copyable.h"
1213
#include "flutter/fml/message_loop.h"
1314
#include "flutter/fml/synchronization/count_down_latch.h"
1415
#include "flutter/fml/synchronization/waitable_event.h"
1516
#include "flutter/shell/common/platform_view.h"
1617
#include "flutter/shell/common/rasterizer.h"
1718
#include "flutter/shell/common/shell_test.h"
19+
#include "flutter/shell/common/switches.h"
1820
#include "flutter/shell/common/thread_host.h"
1921
#include "flutter/testing/testing.h"
2022

@@ -274,5 +276,42 @@ TEST_F(ShellTest, SecondaryIsolateBindingsAreSetupViaShellSettings) {
274276
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
275277
}
276278

279+
TEST_F(ShellTest, BlacklistedDartVMFlag) {
280+
// Run this test in a thread-safe manner, otherwise gtest will complain.
281+
::testing::FLAGS_gtest_death_test_style = "threadsafe";
282+
283+
const std::vector<fml::CommandLine::Option> options = {
284+
fml::CommandLine::Option("dart-flags", "--verify_after_gc")};
285+
fml::CommandLine command_line("", options, std::vector<std::string>());
286+
287+
#if FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE && \
288+
FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_DYNAMIC_RELEASE
289+
// Upon encountering a non-whitelisted Dart flag the process terminates.
290+
const char* expected =
291+
"Encountered blacklisted Dart VM flag: --verify_after_gc";
292+
ASSERT_DEATH(flutter::SettingsFromCommandLine(command_line), expected);
293+
#else
294+
flutter::Settings settings = flutter::SettingsFromCommandLine(command_line);
295+
EXPECT_EQ(settings.dart_flags.size(), 0u);
296+
#endif
297+
}
298+
299+
TEST_F(ShellTest, WhitelistedDartVMFlag) {
300+
const std::vector<fml::CommandLine::Option> options = {
301+
fml::CommandLine::Option("dart-flags",
302+
"--max_profile_depth 1,--trace_service")};
303+
fml::CommandLine command_line("", options, std::vector<std::string>());
304+
flutter::Settings settings = flutter::SettingsFromCommandLine(command_line);
305+
306+
#if FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE && \
307+
FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_DYNAMIC_RELEASE
308+
EXPECT_EQ(settings.dart_flags.size(), 2u);
309+
EXPECT_EQ(settings.dart_flags[0], "--max_profile_depth 1");
310+
EXPECT_EQ(settings.dart_flags[1], "--trace_service");
311+
#else
312+
EXPECT_EQ(settings.dart_flags.size(), 0u);
313+
#endif
314+
}
315+
277316
} // namespace testing
278317
} // namespace flutter

shell/common/switches.cc

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "flutter/fml/native_library.h"
1313
#include "flutter/fml/paths.h"
14+
#include "flutter/fml/size.h"
1415
#include "flutter/fml/string_view.h"
1516
#include "flutter/shell/version/version.h"
1617

@@ -36,6 +37,18 @@ struct SwitchDesc {
3637
#define DEF_SWITCHES_END };
3738
// clang-format on
3839

40+
#if FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE && \
41+
FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_DYNAMIC_RELEASE
42+
43+
// List of common and safe VM flags to allow to be passed directly to the VM.
44+
static const std::string gDartFlagsWhitelist[] = {
45+
"--max_profile_depth", "--profile_period", "--random_seed",
46+
"--trace_profiler", "--trace_profiler_verbose", "--trace_service",
47+
"--trace_service_verbose",
48+
};
49+
50+
#endif
51+
3952
// Include again for struct definition.
4053
#include "flutter/shell/common/switches.h"
4154

@@ -102,6 +115,24 @@ const fml::StringView FlagForSwitch(Switch swtch) {
102115
return fml::StringView();
103116
}
104117

118+
#if FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE && \
119+
FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_DYNAMIC_RELEASE
120+
121+
static bool IsWhitelistedDartVMFlag(const std::string& flag) {
122+
for (uint32_t i = 0; i < fml::size(gDartFlagsWhitelist); ++i) {
123+
const std::string& allowed = gDartFlagsWhitelist[i];
124+
// Check that the prefix of the flag matches one of the whitelisted flags.
125+
// We don't need to worry about cases like "--safe --sneaky_dangerous" as
126+
// the VM will discard these as a single unrecognized flag.
127+
if (std::equal(allowed.begin(), allowed.end(), flag.begin())) {
128+
return true;
129+
}
130+
}
131+
return false;
132+
}
133+
134+
#endif
135+
105136
template <typename T>
106137
static bool GetSwitchValue(const fml::CommandLine& command_line,
107138
Switch sw,
@@ -260,18 +291,24 @@ Settings SettingsFromCommandLine(const fml::CommandLine& command_line) {
260291
settings.use_test_fonts =
261292
command_line.HasOption(FlagForSwitch(Switch::UseTestFonts));
262293

294+
#if FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE && \
295+
FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_DYNAMIC_RELEASE
263296
command_line.GetOptionValue(FlagForSwitch(Switch::LogTag), &settings.log_tag);
264297
std::string all_dart_flags;
265298
if (command_line.GetOptionValue(FlagForSwitch(Switch::DartFlags),
266299
&all_dart_flags)) {
267300
std::stringstream stream(all_dart_flags);
268-
std::istream_iterator<std::string> end;
269-
for (std::istream_iterator<std::string> it(stream); it != end; ++it)
270-
settings.dart_flags.push_back(*it);
301+
std::string flag;
302+
303+
// Assume that individual flags are comma separated.
304+
while (std::getline(stream, flag, ',')) {
305+
if (!IsWhitelistedDartVMFlag(flag)) {
306+
FML_LOG(FATAL) << "Encountered blacklisted Dart VM flag: " << flag;
307+
}
308+
settings.dart_flags.push_back(flag);
309+
}
271310
}
272311

273-
#if FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE && \
274-
FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_DYNAMIC_RELEASE
275312
settings.trace_skia =
276313
command_line.HasOption(FlagForSwitch(Switch::TraceSkia));
277314
settings.trace_systrace =

shell/platform/android/io/flutter/app/FlutterActivityDelegate.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,13 @@ private static String[] getArgsFromIntent(Intent intent) {
312312
if (intent.getBooleanExtra("verbose-logging", false)) {
313313
args.add("--verbose-logging");
314314
}
315+
// NOTE: all flags provided with this argument are subject to filtering
316+
// based on a whitelist in shell/common/switches.cc. If any flag provided
317+
// is not present in the whitelist, the process will immediately
318+
// terminate.
319+
if (intent.hasExtra("dart-flags")) {
320+
args.add("--dart-flags=" + intent.getStringExtra("dart-flags"));
321+
}
315322
if (!args.isEmpty()) {
316323
String[] argsArray = new String[args.size()];
317324
return args.toArray(argsArray);

0 commit comments

Comments
 (0)