flag.cc (25022B)
1 // 2 // Copyright 2019 The Abseil Authors. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // https://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 #include "absl/flags/internal/flag.h" 17 18 #include <assert.h> 19 #include <stddef.h> 20 #include <stdint.h> 21 #include <string.h> 22 23 #include <array> 24 #include <atomic> 25 #include <cstring> 26 #include <memory> 27 #include <string> 28 #include <typeinfo> 29 #include <vector> 30 31 #include "absl/base/attributes.h" 32 #include "absl/base/call_once.h" 33 #include "absl/base/casts.h" 34 #include "absl/base/config.h" 35 #include "absl/base/const_init.h" 36 #include "absl/base/dynamic_annotations.h" 37 #include "absl/base/no_destructor.h" 38 #include "absl/base/optimization.h" 39 #include "absl/base/thread_annotations.h" 40 #include "absl/flags/config.h" 41 #include "absl/flags/internal/commandlineflag.h" 42 #include "absl/flags/usage_config.h" 43 #include "absl/memory/memory.h" 44 #include "absl/strings/str_cat.h" 45 #include "absl/strings/string_view.h" 46 #include "absl/synchronization/mutex.h" 47 48 namespace absl { 49 ABSL_NAMESPACE_BEGIN 50 namespace flags_internal { 51 52 // The help message indicating that the commandline flag has been stripped. It 53 // will not show up when doing "-help" and its variants. The flag is stripped 54 // if ABSL_FLAGS_STRIP_HELP is set to 1 before including absl/flags/flag.h 55 const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001"; 56 57 namespace { 58 59 // Currently we only validate flag values for user-defined flag types. 60 bool ShouldValidateFlagValue(FlagFastTypeId flag_type_id) { 61 #define DONT_VALIDATE(T, _) \ 62 if (flag_type_id == base_internal::FastTypeId<T>()) return false; 63 ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(DONT_VALIDATE) 64 #undef DONT_VALIDATE 65 66 return true; 67 } 68 69 // RAII helper used to temporarily unlock and relock `absl::Mutex`. 70 // This is used when we need to ensure that locks are released while 71 // invoking user supplied callbacks and then reacquired, since callbacks may 72 // need to acquire these locks themselves. 73 class MutexRelock { 74 public: 75 explicit MutexRelock(absl::Mutex& mu) : mu_(mu) { mu_.Unlock(); } 76 ~MutexRelock() { mu_.Lock(); } 77 78 MutexRelock(const MutexRelock&) = delete; 79 MutexRelock& operator=(const MutexRelock&) = delete; 80 81 private: 82 absl::Mutex& mu_; 83 }; 84 85 // This is a freelist of leaked flag values and guard for its access. 86 // When we can't guarantee it is safe to reuse the memory for flag values, 87 // we move the memory to the freelist where it lives indefinitely, so it can 88 // still be safely accessed. This also prevents leak checkers from complaining 89 // about the leaked memory that can no longer be accessed through any pointer. 90 absl::Mutex* FreelistMutex() { 91 static absl::NoDestructor<absl::Mutex> mutex; 92 return mutex.get(); 93 } 94 ABSL_CONST_INIT std::vector<void*>* s_freelist ABSL_GUARDED_BY(FreelistMutex()) 95 ABSL_PT_GUARDED_BY(FreelistMutex()) = nullptr; 96 97 void AddToFreelist(void* p) { 98 absl::MutexLock l(FreelistMutex()); 99 if (!s_freelist) { 100 s_freelist = new std::vector<void*>; 101 } 102 s_freelist->push_back(p); 103 } 104 105 } // namespace 106 107 /////////////////////////////////////////////////////////////////////////////// 108 109 uint64_t NumLeakedFlagValues() { 110 absl::MutexLock l(FreelistMutex()); 111 return s_freelist == nullptr ? 0u : s_freelist->size(); 112 } 113 114 /////////////////////////////////////////////////////////////////////////////// 115 // Persistent state of the flag data. 116 117 class FlagImpl; 118 119 class FlagState : public flags_internal::FlagStateInterface { 120 public: 121 template <typename V> 122 FlagState(FlagImpl& flag_impl, const V& v, bool modified, 123 bool on_command_line, int64_t counter) 124 : flag_impl_(flag_impl), 125 value_(v), 126 modified_(modified), 127 on_command_line_(on_command_line), 128 counter_(counter) {} 129 130 ~FlagState() override { 131 if (flag_impl_.ValueStorageKind() != FlagValueStorageKind::kHeapAllocated && 132 flag_impl_.ValueStorageKind() != FlagValueStorageKind::kSequenceLocked) 133 return; 134 flags_internal::Delete(flag_impl_.op_, value_.heap_allocated); 135 } 136 137 private: 138 friend class FlagImpl; 139 140 // Restores the flag to the saved state. 141 void Restore() const override { 142 if (!flag_impl_.RestoreState(*this)) return; 143 144 ABSL_INTERNAL_LOG(INFO, 145 absl::StrCat("Restore saved value of ", flag_impl_.Name(), 146 " to: ", flag_impl_.CurrentValue())); 147 } 148 149 // Flag and saved flag data. 150 FlagImpl& flag_impl_; 151 union SavedValue { 152 explicit SavedValue(void* v) : heap_allocated(v) {} 153 explicit SavedValue(int64_t v) : one_word(v) {} 154 155 void* heap_allocated; 156 int64_t one_word; 157 } value_; 158 bool modified_; 159 bool on_command_line_; 160 int64_t counter_; 161 }; 162 163 /////////////////////////////////////////////////////////////////////////////// 164 // Flag implementation, which does not depend on flag value type. 165 166 DynValueDeleter::DynValueDeleter(FlagOpFn op_arg) : op(op_arg) {} 167 168 void DynValueDeleter::operator()(void* ptr) const { 169 if (op == nullptr) return; 170 171 Delete(op, ptr); 172 } 173 174 MaskedPointer::MaskedPointer(ptr_t rhs, bool is_candidate) : ptr_(rhs) { 175 if (is_candidate) { 176 ApplyMask(kUnprotectedReadCandidate); 177 } 178 } 179 180 bool MaskedPointer::IsUnprotectedReadCandidate() const { 181 return CheckMask(kUnprotectedReadCandidate); 182 } 183 184 bool MaskedPointer::HasBeenRead() const { return CheckMask(kHasBeenRead); } 185 186 void MaskedPointer::Set(FlagOpFn op, const void* src, bool is_candidate) { 187 flags_internal::Copy(op, src, Ptr()); 188 if (is_candidate) { 189 ApplyMask(kUnprotectedReadCandidate); 190 } 191 } 192 void MaskedPointer::MarkAsRead() { ApplyMask(kHasBeenRead); } 193 194 void MaskedPointer::ApplyMask(mask_t mask) { 195 ptr_ = reinterpret_cast<ptr_t>(reinterpret_cast<mask_t>(ptr_) | mask); 196 } 197 bool MaskedPointer::CheckMask(mask_t mask) const { 198 return (reinterpret_cast<mask_t>(ptr_) & mask) != 0; 199 } 200 201 void FlagImpl::Init() { 202 new (&data_guard_) absl::Mutex; 203 204 auto def_kind = static_cast<FlagDefaultKind>(def_kind_); 205 206 switch (ValueStorageKind()) { 207 case FlagValueStorageKind::kValueAndInitBit: 208 case FlagValueStorageKind::kOneWordAtomic: { 209 alignas(int64_t) std::array<char, sizeof(int64_t)> buf{}; 210 if (def_kind == FlagDefaultKind::kGenFunc) { 211 (*default_value_.gen_func)(buf.data()); 212 } else { 213 assert(def_kind != FlagDefaultKind::kDynamicValue); 214 std::memcpy(buf.data(), &default_value_, Sizeof(op_)); 215 } 216 if (ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit) { 217 // We presume here the memory layout of FlagValueAndInitBit struct. 218 uint8_t initialized = 1; 219 std::memcpy(buf.data() + Sizeof(op_), &initialized, 220 sizeof(initialized)); 221 } 222 // Type can contain valid uninitialized bits, e.g. padding. 223 ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(buf.data(), buf.size()); 224 OneWordValue().store(absl::bit_cast<int64_t>(buf), 225 std::memory_order_release); 226 break; 227 } 228 case FlagValueStorageKind::kSequenceLocked: { 229 // For this storage kind the default_value_ always points to gen_func 230 // during initialization. 231 assert(def_kind == FlagDefaultKind::kGenFunc); 232 (*default_value_.gen_func)(AtomicBufferValue()); 233 break; 234 } 235 case FlagValueStorageKind::kHeapAllocated: 236 // For this storage kind the default_value_ always points to gen_func 237 // during initialization. 238 assert(def_kind == FlagDefaultKind::kGenFunc); 239 // Flag value initially points to the internal buffer. 240 MaskedPointer ptr_value = PtrStorage().load(std::memory_order_acquire); 241 (*default_value_.gen_func)(ptr_value.Ptr()); 242 // Default value is a candidate for an unprotected read. 243 PtrStorage().store(MaskedPointer(ptr_value.Ptr(), true), 244 std::memory_order_release); 245 break; 246 } 247 seq_lock_.MarkInitialized(); 248 } 249 250 absl::Mutex* FlagImpl::DataGuard() const { 251 absl::call_once(const_cast<FlagImpl*>(this)->init_control_, &FlagImpl::Init, 252 const_cast<FlagImpl*>(this)); 253 254 // data_guard_ is initialized inside Init. 255 return reinterpret_cast<absl::Mutex*>(&data_guard_); 256 } 257 258 void FlagImpl::AssertValidType(FlagFastTypeId rhs_type_id, 259 const std::type_info* (*gen_rtti)()) const { 260 FlagFastTypeId lhs_type_id = flags_internal::FastTypeId(op_); 261 262 // `rhs_type_id` is the fast type id corresponding to the declaration 263 // visible at the call site. `lhs_type_id` is the fast type id 264 // corresponding to the type specified in flag definition. They must match 265 // for this operation to be well-defined. 266 if (ABSL_PREDICT_TRUE(lhs_type_id == rhs_type_id)) return; 267 268 const std::type_info* lhs_runtime_type_id = 269 flags_internal::RuntimeTypeId(op_); 270 const std::type_info* rhs_runtime_type_id = (*gen_rtti)(); 271 272 if (lhs_runtime_type_id == rhs_runtime_type_id) return; 273 274 #ifdef ABSL_INTERNAL_HAS_RTTI 275 if (*lhs_runtime_type_id == *rhs_runtime_type_id) return; 276 #endif 277 278 ABSL_INTERNAL_LOG( 279 FATAL, absl::StrCat("Flag '", Name(), 280 "' is defined as one type and declared as another")); 281 } 282 283 std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const { 284 void* res = nullptr; 285 switch (DefaultKind()) { 286 case FlagDefaultKind::kDynamicValue: 287 res = flags_internal::Clone(op_, default_value_.dynamic_value); 288 break; 289 case FlagDefaultKind::kGenFunc: 290 res = flags_internal::Alloc(op_); 291 (*default_value_.gen_func)(res); 292 break; 293 default: 294 res = flags_internal::Clone(op_, &default_value_); 295 break; 296 } 297 return {res, DynValueDeleter{op_}}; 298 } 299 300 void FlagImpl::StoreValue(const void* src, ValueSource source) { 301 switch (ValueStorageKind()) { 302 case FlagValueStorageKind::kValueAndInitBit: 303 case FlagValueStorageKind::kOneWordAtomic: { 304 // Load the current value to avoid setting 'init' bit manually. 305 int64_t one_word_val = OneWordValue().load(std::memory_order_acquire); 306 std::memcpy(&one_word_val, src, Sizeof(op_)); 307 OneWordValue().store(one_word_val, std::memory_order_release); 308 seq_lock_.IncrementModificationCount(); 309 break; 310 } 311 case FlagValueStorageKind::kSequenceLocked: { 312 seq_lock_.Write(AtomicBufferValue(), src, Sizeof(op_)); 313 break; 314 } 315 case FlagValueStorageKind::kHeapAllocated: 316 MaskedPointer ptr_value = PtrStorage().load(std::memory_order_acquire); 317 318 if (ptr_value.IsUnprotectedReadCandidate() && ptr_value.HasBeenRead()) { 319 // If current value is a candidate for an unprotected read and if it was 320 // already read at least once, follow up reads (if any) are done without 321 // mutex protection. We can't guarantee it is safe to reuse this memory 322 // since it may have been accessed by another thread concurrently, so 323 // instead we move the memory to a freelist so it can still be safely 324 // accessed, and allocate a new one for the new value. 325 AddToFreelist(ptr_value.Ptr()); 326 ptr_value = MaskedPointer(Clone(op_, src), source == kCommandLine); 327 } else { 328 // Current value either was set programmatically or was never read. 329 // We can reuse the memory since all accesses to this value (if any) 330 // were protected by mutex. That said, if a new value comes from command 331 // line it now becomes a candidate for an unprotected read. 332 ptr_value.Set(op_, src, source == kCommandLine); 333 } 334 335 PtrStorage().store(ptr_value, std::memory_order_release); 336 seq_lock_.IncrementModificationCount(); 337 break; 338 } 339 modified_ = true; 340 InvokeCallback(); 341 } 342 343 absl::string_view FlagImpl::Name() const { return name_; } 344 345 absl::string_view FlagImpl::TypeName() const { return type_name_; } 346 347 std::string FlagImpl::Filename() const { 348 return flags_internal::GetUsageConfig().normalize_filename(filename_); 349 } 350 351 std::string FlagImpl::Help() const { 352 return HelpSourceKind() == FlagHelpKind::kLiteral ? help_.literal 353 : help_.gen_func(); 354 } 355 356 FlagFastTypeId FlagImpl::TypeId() const { 357 return flags_internal::FastTypeId(op_); 358 } 359 360 int64_t FlagImpl::ModificationCount() const { 361 return seq_lock_.ModificationCount(); 362 } 363 364 bool FlagImpl::IsSpecifiedOnCommandLine() const { 365 absl::MutexLock l(DataGuard()); 366 return on_command_line_; 367 } 368 369 std::string FlagImpl::DefaultValue() const { 370 absl::MutexLock l(DataGuard()); 371 372 auto obj = MakeInitValue(); 373 return flags_internal::Unparse(op_, obj.get()); 374 } 375 376 std::string FlagImpl::CurrentValue() const { 377 auto* guard = DataGuard(); // Make sure flag initialized 378 switch (ValueStorageKind()) { 379 case FlagValueStorageKind::kValueAndInitBit: 380 case FlagValueStorageKind::kOneWordAtomic: { 381 const auto one_word_val = 382 absl::bit_cast<std::array<char, sizeof(int64_t)>>( 383 OneWordValue().load(std::memory_order_acquire)); 384 return flags_internal::Unparse(op_, one_word_val.data()); 385 } 386 case FlagValueStorageKind::kSequenceLocked: { 387 std::unique_ptr<void, DynValueDeleter> cloned(flags_internal::Alloc(op_), 388 DynValueDeleter{op_}); 389 ReadSequenceLockedData(cloned.get()); 390 return flags_internal::Unparse(op_, cloned.get()); 391 } 392 case FlagValueStorageKind::kHeapAllocated: { 393 absl::MutexLock l(guard); 394 return flags_internal::Unparse( 395 op_, PtrStorage().load(std::memory_order_acquire).Ptr()); 396 } 397 } 398 399 return ""; 400 } 401 402 void FlagImpl::SetCallback(const FlagCallbackFunc mutation_callback) { 403 absl::MutexLock l(DataGuard()); 404 405 if (callback_ == nullptr) { 406 callback_ = new FlagCallback; 407 } 408 callback_->func = mutation_callback; 409 410 InvokeCallback(); 411 } 412 413 void FlagImpl::InvokeCallback() const { 414 if (!callback_) return; 415 416 // Make a copy of the C-style function pointer that we are about to invoke 417 // before we release the lock guarding it. 418 FlagCallbackFunc cb = callback_->func; 419 420 // If the flag has a mutation callback this function invokes it. While the 421 // callback is being invoked the primary flag's mutex is unlocked and it is 422 // re-locked back after call to callback is completed. Callback invocation is 423 // guarded by flag's secondary mutex instead which prevents concurrent 424 // callback invocation. Note that it is possible for other thread to grab the 425 // primary lock and update flag's value at any time during the callback 426 // invocation. This is by design. Callback can get a value of the flag if 427 // necessary, but it might be different from the value initiated the callback 428 // and it also can be different by the time the callback invocation is 429 // completed. Requires that *primary_lock be held in exclusive mode; it may be 430 // released and reacquired by the implementation. 431 MutexRelock relock(*DataGuard()); 432 absl::MutexLock lock(&callback_->guard); 433 cb(); 434 } 435 436 std::unique_ptr<FlagStateInterface> FlagImpl::SaveState() { 437 absl::MutexLock l(DataGuard()); 438 439 bool modified = modified_; 440 bool on_command_line = on_command_line_; 441 switch (ValueStorageKind()) { 442 case FlagValueStorageKind::kValueAndInitBit: 443 case FlagValueStorageKind::kOneWordAtomic: { 444 return absl::make_unique<FlagState>( 445 *this, OneWordValue().load(std::memory_order_acquire), modified, 446 on_command_line, ModificationCount()); 447 } 448 case FlagValueStorageKind::kSequenceLocked: { 449 void* cloned = flags_internal::Alloc(op_); 450 // Read is guaranteed to be successful because we hold the lock. 451 bool success = 452 seq_lock_.TryRead(cloned, AtomicBufferValue(), Sizeof(op_)); 453 assert(success); 454 static_cast<void>(success); 455 return absl::make_unique<FlagState>(*this, cloned, modified, 456 on_command_line, ModificationCount()); 457 } 458 case FlagValueStorageKind::kHeapAllocated: { 459 return absl::make_unique<FlagState>( 460 *this, 461 flags_internal::Clone( 462 op_, PtrStorage().load(std::memory_order_acquire).Ptr()), 463 modified, on_command_line, ModificationCount()); 464 } 465 } 466 return nullptr; 467 } 468 469 bool FlagImpl::RestoreState(const FlagState& flag_state) { 470 absl::MutexLock l(DataGuard()); 471 if (flag_state.counter_ == ModificationCount()) { 472 return false; 473 } 474 475 switch (ValueStorageKind()) { 476 case FlagValueStorageKind::kValueAndInitBit: 477 case FlagValueStorageKind::kOneWordAtomic: 478 StoreValue(&flag_state.value_.one_word, kProgrammaticChange); 479 break; 480 case FlagValueStorageKind::kSequenceLocked: 481 case FlagValueStorageKind::kHeapAllocated: 482 StoreValue(flag_state.value_.heap_allocated, kProgrammaticChange); 483 break; 484 } 485 486 modified_ = flag_state.modified_; 487 on_command_line_ = flag_state.on_command_line_; 488 489 return true; 490 } 491 492 template <typename StorageT> 493 StorageT* FlagImpl::OffsetValue() const { 494 char* p = reinterpret_cast<char*>(const_cast<FlagImpl*>(this)); 495 // The offset is deduced via Flag value type specific op_. 496 ptrdiff_t offset = flags_internal::ValueOffset(op_); 497 498 return reinterpret_cast<StorageT*>(p + offset); 499 } 500 501 std::atomic<uint64_t>* FlagImpl::AtomicBufferValue() const { 502 assert(ValueStorageKind() == FlagValueStorageKind::kSequenceLocked); 503 return OffsetValue<std::atomic<uint64_t>>(); 504 } 505 506 std::atomic<int64_t>& FlagImpl::OneWordValue() const { 507 assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic || 508 ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit); 509 return OffsetValue<FlagOneWordValue>()->value; 510 } 511 512 std::atomic<MaskedPointer>& FlagImpl::PtrStorage() const { 513 assert(ValueStorageKind() == FlagValueStorageKind::kHeapAllocated); 514 return OffsetValue<FlagMaskedPointerValue>()->value; 515 } 516 517 // Attempts to parse supplied `value` string using parsing routine in the `flag` 518 // argument. If parsing successful, this function replaces the dst with newly 519 // parsed value. In case if any error is encountered in either step, the error 520 // message is stored in 'err' 521 std::unique_ptr<void, DynValueDeleter> FlagImpl::TryParse( 522 absl::string_view value, std::string& err) const { 523 std::unique_ptr<void, DynValueDeleter> tentative_value = MakeInitValue(); 524 525 std::string parse_err; 526 if (!flags_internal::Parse(op_, value, tentative_value.get(), &parse_err)) { 527 absl::string_view err_sep = parse_err.empty() ? "" : "; "; 528 err = absl::StrCat("Illegal value '", value, "' specified for flag '", 529 Name(), "'", err_sep, parse_err); 530 return nullptr; 531 } 532 533 return tentative_value; 534 } 535 536 void FlagImpl::Read(void* dst) const { 537 auto* guard = DataGuard(); // Make sure flag initialized 538 switch (ValueStorageKind()) { 539 case FlagValueStorageKind::kValueAndInitBit: 540 case FlagValueStorageKind::kOneWordAtomic: { 541 const int64_t one_word_val = 542 OneWordValue().load(std::memory_order_acquire); 543 std::memcpy(dst, &one_word_val, Sizeof(op_)); 544 break; 545 } 546 case FlagValueStorageKind::kSequenceLocked: { 547 ReadSequenceLockedData(dst); 548 break; 549 } 550 case FlagValueStorageKind::kHeapAllocated: { 551 absl::MutexLock l(guard); 552 MaskedPointer ptr_value = PtrStorage().load(std::memory_order_acquire); 553 554 flags_internal::CopyConstruct(op_, ptr_value.Ptr(), dst); 555 556 // For unprotected read candidates, mark that the value as has been read. 557 if (ptr_value.IsUnprotectedReadCandidate() && !ptr_value.HasBeenRead()) { 558 ptr_value.MarkAsRead(); 559 PtrStorage().store(ptr_value, std::memory_order_release); 560 } 561 break; 562 } 563 } 564 } 565 566 int64_t FlagImpl::ReadOneWord() const { 567 assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic || 568 ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit); 569 auto* guard = DataGuard(); // Make sure flag initialized 570 (void)guard; 571 return OneWordValue().load(std::memory_order_acquire); 572 } 573 574 bool FlagImpl::ReadOneBool() const { 575 assert(ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit); 576 auto* guard = DataGuard(); // Make sure flag initialized 577 (void)guard; 578 return absl::bit_cast<FlagValueAndInitBit<bool>>( 579 OneWordValue().load(std::memory_order_acquire)) 580 .value; 581 } 582 583 void FlagImpl::ReadSequenceLockedData(void* dst) const { 584 size_t size = Sizeof(op_); 585 // Attempt to read using the sequence lock. 586 if (ABSL_PREDICT_TRUE(seq_lock_.TryRead(dst, AtomicBufferValue(), size))) { 587 return; 588 } 589 // We failed due to contention. Acquire the lock to prevent contention 590 // and try again. 591 absl::ReaderMutexLock l(DataGuard()); 592 bool success = seq_lock_.TryRead(dst, AtomicBufferValue(), size); 593 assert(success); 594 static_cast<void>(success); 595 } 596 597 void FlagImpl::Write(const void* src) { 598 absl::MutexLock l(DataGuard()); 599 600 if (ShouldValidateFlagValue(flags_internal::FastTypeId(op_))) { 601 std::unique_ptr<void, DynValueDeleter> obj{flags_internal::Clone(op_, src), 602 DynValueDeleter{op_}}; 603 std::string ignored_error; 604 std::string src_as_str = flags_internal::Unparse(op_, src); 605 if (!flags_internal::Parse(op_, src_as_str, obj.get(), &ignored_error)) { 606 ABSL_INTERNAL_LOG(ERROR, absl::StrCat("Attempt to set flag '", Name(), 607 "' to invalid value ", src_as_str)); 608 } 609 } 610 611 StoreValue(src, kProgrammaticChange); 612 } 613 614 // Sets the value of the flag based on specified string `value`. If the flag 615 // was successfully set to new value, it returns true. Otherwise, sets `err` 616 // to indicate the error, leaves the flag unchanged, and returns false. There 617 // are three ways to set the flag's value: 618 // * Update the current flag value 619 // * Update the flag's default value 620 // * Update the current flag value if it was never set before 621 // The mode is selected based on 'set_mode' parameter. 622 bool FlagImpl::ParseFrom(absl::string_view value, FlagSettingMode set_mode, 623 ValueSource source, std::string& err) { 624 absl::MutexLock l(DataGuard()); 625 626 switch (set_mode) { 627 case SET_FLAGS_VALUE: { 628 // set or modify the flag's value 629 auto tentative_value = TryParse(value, err); 630 if (!tentative_value) return false; 631 632 StoreValue(tentative_value.get(), source); 633 634 if (source == kCommandLine) { 635 on_command_line_ = true; 636 } 637 break; 638 } 639 case SET_FLAG_IF_DEFAULT: { 640 // set the flag's value, but only if it hasn't been set by someone else 641 if (modified_) { 642 // TODO(rogeeff): review and fix this semantic. Currently we do not fail 643 // in this case if flag is modified. This is misleading since the flag's 644 // value is not updated even though we return true. 645 // *err = absl::StrCat(Name(), " is already set to ", 646 // CurrentValue(), "\n"); 647 // return false; 648 return true; 649 } 650 auto tentative_value = TryParse(value, err); 651 if (!tentative_value) return false; 652 653 StoreValue(tentative_value.get(), source); 654 break; 655 } 656 case SET_FLAGS_DEFAULT: { 657 auto tentative_value = TryParse(value, err); 658 if (!tentative_value) return false; 659 660 if (DefaultKind() == FlagDefaultKind::kDynamicValue) { 661 void* old_value = default_value_.dynamic_value; 662 default_value_.dynamic_value = tentative_value.release(); 663 tentative_value.reset(old_value); 664 } else { 665 default_value_.dynamic_value = tentative_value.release(); 666 def_kind_ = static_cast<uint8_t>(FlagDefaultKind::kDynamicValue); 667 } 668 669 if (!modified_) { 670 // Need to set both default value *and* current, in this case. 671 StoreValue(default_value_.dynamic_value, source); 672 modified_ = false; 673 } 674 break; 675 } 676 } 677 678 return true; 679 } 680 681 void FlagImpl::CheckDefaultValueParsingRoundtrip() const { 682 std::string v = DefaultValue(); 683 684 absl::MutexLock lock(DataGuard()); 685 686 auto dst = MakeInitValue(); 687 std::string error; 688 if (!flags_internal::Parse(op_, v, dst.get(), &error)) { 689 ABSL_INTERNAL_LOG( 690 FATAL, 691 absl::StrCat("Flag ", Name(), " (from ", Filename(), 692 "): string form of default value '", v, 693 "' could not be parsed; error=", error)); 694 } 695 696 // We do not compare dst to def since parsing/unparsing may make 697 // small changes, e.g., precision loss for floating point types. 698 } 699 700 bool FlagImpl::ValidateInputValue(absl::string_view value) const { 701 absl::MutexLock l(DataGuard()); 702 703 auto obj = MakeInitValue(); 704 std::string ignored_error; 705 return flags_internal::Parse(op_, value, obj.get(), &ignored_error); 706 } 707 708 } // namespace flags_internal 709 ABSL_NAMESPACE_END 710 } // namespace absl