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