Coverage Report

Created: 2024-09-23 06:29

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