Coverage Report

Created: 2023-09-25 06:27

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