Coverage Report

Created: 2025-08-25 06:55

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