[flags] Add flag to freeze flags after initialization

This adds a new flag to freeze all flag values after initializing V8.
For now, the only effect is that future calls to {SetFlagsFromString},
{SetFlagsFromCommandLine} or {EnforceFlagImplications} will fail.
In the future (once tests and embedders are fixed to not change flags
after initialization) we plan to actually protect flag values via memory
protection.

R=cbruni@chromium.org

Bug: v8:12887
Change-Id: I7974bb9b86715694122f788e08952f7dcc3acdbd
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3679099
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80914}
This commit is contained in:
Clemens Backes 2022-06-02 12:25:53 +02:00 committed by V8 LUCI CQ
parent f745216990
commit f363be9c66
4 changed files with 32 additions and 2 deletions

View File

@ -1886,6 +1886,9 @@ DEFINE_BOOL(
"Fuzzers use this flag to signal that they are ... fuzzing. This causes "
"intrinsics to fail silently (e.g. return undefined) on invalid usage.")
DEFINE_BOOL(freeze_flags_after_init, false,
"Disallow changes to flag values after initializing V8")
// mksnapshot.cc
DEFINE_STRING(embedded_src, nullptr,
"Path for the generated embedded data file. (mksnapshot only)")

View File

@ -499,7 +499,8 @@ std::ostream& operator<<(std::ostream& os, const Flag& flag) {
namespace {
static std::atomic<uint32_t> flag_hash(0);
static std::atomic<uint32_t> flag_hash{0};
static std::atomic<bool> flags_frozen{false};
void ComputeFlagListHash() {
std::ostringstream modified_args_as_string;
@ -590,6 +591,7 @@ bool TryParseUnsigned(Flag* flag, const char* arg, const char* value,
// static
int FlagList::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags,
HelpOptions help_options) {
CHECK(!IsFrozen());
int return_code = 0;
// parse arguments
for (int i = 1; i < *argc;) {
@ -784,8 +786,20 @@ int FlagList::SetFlagsFromString(const char* str, size_t len) {
return SetFlagsFromCommandLine(&argc, argv.begin(), false);
}
// static
void FlagList::FreezeFlags() {
flags_frozen.store(true, std::memory_order_relaxed);
}
// static
bool FlagList::IsFrozen() {
return flags_frozen.load(std::memory_order_relaxed);
}
// static
void FlagList::ResetAllFlags() {
// Reset is allowed even if flags are frozen. They stay frozen though, because
// they are not expected to ever be used again.
flag_hash = 0;
for (size_t i = 0; i < num_flags; ++i) {
flags[i].Reset();
@ -843,6 +857,7 @@ bool TriggerImplication(bool premise, const char* premise_name,
// static
void FlagList::EnforceFlagImplications() {
CHECK(!IsFrozen());
flag_hash = 0;
bool changed;
int iteration = 0;

View File

@ -61,6 +61,13 @@ class V8_EXPORT_PRIVATE FlagList {
// and then calls SetFlagsFromCommandLine() and returns its result.
static int SetFlagsFromString(const char* str, size_t len);
// Freeze the current flag values (disallow changes via the API).
// TODO(12887): Actually write-protect the flags.
static void FreezeFlags();
// Returns true if the flags are currently frozen.
static bool IsFrozen();
// Reset all flags to their default value.
static void ResetAllFlags();

View File

@ -235,9 +235,14 @@ void V8::Initialize() {
if (FLAG_print_flag_values) FlagList::PrintValues();
// Initialize the default FlagList::Hash
// Initialize the default FlagList::Hash.
FlagList::Hash();
// Before initializing internals, freeze the flags such that further changes
// are not allowed. Global initialization of the Isolate or the WasmEngine
// already reads flags, so they should not be changed afterwards.
if (FLAG_freeze_flags_after_init) FlagList::FreezeFlags();
#if defined(V8_USE_PERFETTO)
if (perfetto::Tracing::IsInitialized()) TrackEvent::Register();
#endif