| Index: webrtc/base/optional.h
|
| diff --git a/webrtc/base/optional.h b/webrtc/base/optional.h
|
| index e98ab2e3ce7e9765386bcb8cbb47c92f4a7b42fa..b047fabc427871ee9d86fdc3f7ef6397c0f82a46 100644
|
| --- a/webrtc/base/optional.h
|
| +++ b/webrtc/base/optional.h
|
| @@ -15,10 +15,34 @@
|
| #include <memory>
|
| #include <utility>
|
|
|
| +#include "webrtc/base/array_view.h"
|
| #include "webrtc/base/checks.h"
|
| +#include "webrtc/base/sanitizer.h"
|
|
|
| namespace rtc {
|
|
|
| +namespace optional_internal {
|
| +
|
| +#if RTC_HAS_ASAN
|
| +
|
| +// This is a non-inlined function. The optimizer can't see inside it.
|
| +void* FunctionThatDoesNothingImpl(void*);
|
| +
|
| +template <typename T>
|
| +inline T* FunctionThatDoesNothing(T* x) {
|
| + return reinterpret_cast<T*>(
|
| + FunctionThatDoesNothingImpl(reinterpret_cast<void*>(x)));
|
| +}
|
| +
|
| +#else
|
| +
|
| +template <typename T>
|
| +inline T* FunctionThatDoesNothing(T* x) { return x; }
|
| +
|
| +#endif
|
| +
|
| +} // namespace optional_internal
|
| +
|
| // Simple std::optional-wannabe. It either contains a T or not.
|
| //
|
| // A moved-from Optional<T> may only be destroyed, and assigned to if T allows
|
| @@ -59,7 +83,9 @@ template <typename T>
|
| class Optional final {
|
| public:
|
| // Construct an empty Optional.
|
| - Optional() : has_value_(false), empty_('\0') {}
|
| + Optional() : has_value_(false), empty_('\0') {
|
| + PoisonValue();
|
| + }
|
|
|
| // Construct an Optional that contains a value.
|
| explicit Optional(const T& value) : has_value_(true) {
|
| @@ -73,6 +99,8 @@ class Optional final {
|
| Optional(const Optional& m) : has_value_(m.has_value_) {
|
| if (has_value_)
|
| new (&value_) T(m.value_);
|
| + else
|
| + PoisonValue();
|
| }
|
|
|
| // Move constructor: if m has a value, moves the value from m, leaving m
|
| @@ -82,11 +110,15 @@ class Optional final {
|
| Optional(Optional&& m) : has_value_(m.has_value_) {
|
| if (has_value_)
|
| new (&value_) T(std::move(m.value_));
|
| + else
|
| + PoisonValue();
|
| }
|
|
|
| ~Optional() {
|
| if (has_value_)
|
| value_.~T();
|
| + else
|
| + UnpoisonValue();
|
| }
|
|
|
| // Copy assignment. Uses T's copy assignment if both sides have a value, T's
|
| @@ -96,12 +128,14 @@ class Optional final {
|
| if (has_value_) {
|
| value_ = m.value_; // T's copy assignment.
|
| } else {
|
| + UnpoisonValue();
|
| new (&value_) T(m.value_); // T's copy constructor.
|
| has_value_ = true;
|
| }
|
| } else if (has_value_) {
|
| value_.~T();
|
| has_value_ = false;
|
| + PoisonValue();
|
| }
|
| return *this;
|
| }
|
| @@ -114,12 +148,14 @@ class Optional final {
|
| if (has_value_) {
|
| value_ = std::move(m.value_); // T's move assignment.
|
| } else {
|
| + UnpoisonValue();
|
| new (&value_) T(std::move(m.value_)); // T's move constructor.
|
| has_value_ = true;
|
| }
|
| } else if (has_value_) {
|
| value_.~T();
|
| has_value_ = false;
|
| + PoisonValue();
|
| }
|
| return *this;
|
| }
|
| @@ -134,17 +170,21 @@ class Optional final {
|
| swap(m1.value_, m2.value_);
|
| } else {
|
| // Only m1 has a value: move it to m2.
|
| + m2.UnpoisonValue();
|
| new (&m2.value_) T(std::move(m1.value_));
|
| m1.value_.~T(); // Destroy the moved-from value.
|
| m1.has_value_ = false;
|
| m2.has_value_ = true;
|
| + m1.PoisonValue();
|
| }
|
| } else if (m2.has_value_) {
|
| // Only m2 has a value: move it to m1.
|
| + m1.UnpoisonValue();
|
| new (&m1.value_) T(std::move(m2.value_));
|
| m2.value_.~T(); // Destroy the moved-from value.
|
| m1.has_value_ = true;
|
| m2.has_value_ = false;
|
| + m2.PoisonValue();
|
| }
|
| }
|
|
|
| @@ -171,7 +211,11 @@ class Optional final {
|
|
|
| // Dereference with a default value in case we don't have a value.
|
| const T& value_or(const T& default_val) const {
|
| - return has_value_ ? value_ : default_val;
|
| + // The no-op call prevents the compiler from generating optimized code that
|
| + // reads value_ even if !has_value_, but only if FunctionThatDoesNothing is
|
| + // not completely inlined; see its declaration.).
|
| + return has_value_ ? *optional_internal::FunctionThatDoesNothing(&value_)
|
| + : default_val;
|
| }
|
|
|
| // Equality tests. Two Optionals are equal if they contain equivalent values,
|
| @@ -187,6 +231,17 @@ class Optional final {
|
| }
|
|
|
| private:
|
| + // Tell sanitizers that value_ shouldn't be touched.
|
| + void PoisonValue() {
|
| + rtc::AsanPoison(rtc::MakeArrayView(&value_, 1));
|
| + rtc::MsanMarkUninitialized(rtc::MakeArrayView(&value_, 1));
|
| + }
|
| +
|
| + // Tell sanitizers that value_ is OK to touch again.
|
| + void UnpoisonValue() {
|
| + rtc::AsanUnpoison(rtc::MakeArrayView(&value_, 1));
|
| + }
|
| +
|
| bool has_value_; // True iff value_ contains a live value.
|
| union {
|
| // empty_ exists only to make it possible to initialize the union, even when
|
|
|