 Chromium Code Reviews
 Chromium Code Reviews Issue 2289383002:
  rtc::Optional: Tell sanitizers that unset values aren't OK to access  (Closed)
    
  
    Issue 2289383002:
  rtc::Optional: Tell sanitizers that unset values aren't OK to access  (Closed) 
  | OLD | NEW | 
|---|---|
| 1 /* | 1 /* | 
| 2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. | 
| 3 * | 3 * | 
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license | 
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source | 
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found | 
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may | 
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. | 
| 9 */ | 9 */ | 
| 10 | 10 | 
| 11 #ifndef WEBRTC_BASE_OPTIONAL_H_ | 11 #ifndef WEBRTC_BASE_OPTIONAL_H_ | 
| 12 #define WEBRTC_BASE_OPTIONAL_H_ | 12 #define WEBRTC_BASE_OPTIONAL_H_ | 
| 13 | 13 | 
| 14 #include <algorithm> | 14 #include <algorithm> | 
| 15 #include <memory> | 15 #include <memory> | 
| 16 #include <utility> | 16 #include <utility> | 
| 17 | 17 | 
| 18 #include "webrtc/base/array_view.h" | |
| 18 #include "webrtc/base/checks.h" | 19 #include "webrtc/base/checks.h" | 
| 20 #include "webrtc/base/sanitizer.h" | |
| 19 | 21 | 
| 20 namespace rtc { | 22 namespace rtc { | 
| 21 | 23 | 
| 24 namespace internal { | |
| 25 | |
| 26 #if RTC_HAS_ASAN | |
| 27 | |
| 28 // This is a non-inlined function. The optimizer can't see inside it. | |
| 29 void* FunctionThatDoesNothingImpl(void*); | |
| 30 | |
| 31 template <typename T> | |
| 32 inline T* FunctionThatDoesNothing(T* x) { | |
| 33 return reinterpret_cast<T*>( | |
| 34 FunctionThatDoesNothingImpl(reinterpret_cast<void*>(x))); | |
| 35 } | |
| 36 | |
| 37 #else | |
| 38 | |
| 39 template <typename T> | |
| 40 inline T* FunctionThatDoesNothing(T* x) { return x; } | |
| 41 | |
| 42 #endif | |
| 43 | |
| 44 } // namespace internal | |
| 45 | |
| 22 // Simple std::optional-wannabe. It either contains a T or not. | 46 // Simple std::optional-wannabe. It either contains a T or not. | 
| 23 // | 47 // | 
| 24 // A moved-from Optional<T> may only be destroyed, and assigned to if T allows | 48 // A moved-from Optional<T> may only be destroyed, and assigned to if T allows | 
| 25 // being assigned to after having been moved from. Specifically, you may not | 49 // being assigned to after having been moved from. Specifically, you may not | 
| 26 // assume that it just doesn't contain a value anymore. | 50 // assume that it just doesn't contain a value anymore. | 
| 27 // | 51 // | 
| 28 // Examples of good places to use Optional: | 52 // Examples of good places to use Optional: | 
| 29 // | 53 // | 
| 30 // - As a class or struct member, when the member doesn't always have a value: | 54 // - As a class or struct member, when the member doesn't always have a value: | 
| 31 // struct Prisoner { | 55 // struct Prisoner { | 
| (...skipping 20 matching lines...) Expand all Loading... | |
| 52 // Optional<double> when parsing a single number as in the example above | 76 // Optional<double> when parsing a single number as in the example above | 
| 53 // might make sense, but any larger parse job is probably going to need to | 77 // might make sense, but any larger parse job is probably going to need to | 
| 54 // tell the caller what the problem was, not just that there was one. | 78 // tell the caller what the problem was, not just that there was one. | 
| 55 // | 79 // | 
| 56 // TODO(kwiberg): Get rid of this class when the standard library has | 80 // TODO(kwiberg): Get rid of this class when the standard library has | 
| 57 // std::optional (and we're allowed to use it). | 81 // std::optional (and we're allowed to use it). | 
| 58 template <typename T> | 82 template <typename T> | 
| 59 class Optional final { | 83 class Optional final { | 
| 60 public: | 84 public: | 
| 61 // Construct an empty Optional. | 85 // Construct an empty Optional. | 
| 62 Optional() : has_value_(false), empty_('\0') {} | 86 Optional() : has_value_(false), empty_('\0') { | 
| 87 PoisonValue(); | |
| 88 } | |
| 63 | 89 | 
| 64 // Construct an Optional that contains a value. | 90 // Construct an Optional that contains a value. | 
| 65 explicit Optional(const T& value) : has_value_(true) { | 91 explicit Optional(const T& value) : has_value_(true) { | 
| 66 new (&value_) T(value); | 92 new (&value_) T(value); | 
| 67 } | 93 } | 
| 68 explicit Optional(T&& value) : has_value_(true) { | 94 explicit Optional(T&& value) : has_value_(true) { | 
| 69 new (&value_) T(std::move(value)); | 95 new (&value_) T(std::move(value)); | 
| 70 } | 96 } | 
| 71 | 97 | 
| 72 // Copy constructor: copies the value from m if it has one. | 98 // Copy constructor: copies the value from m if it has one. | 
| 73 Optional(const Optional& m) : has_value_(m.has_value_) { | 99 Optional(const Optional& m) : has_value_(m.has_value_) { | 
| 74 if (has_value_) | 100 if (has_value_) | 
| 75 new (&value_) T(m.value_); | 101 new (&value_) T(m.value_); | 
| 102 else | |
| 103 PoisonValue(); | |
| 76 } | 104 } | 
| 77 | 105 | 
| 78 // Move constructor: if m has a value, moves the value from m, leaving m | 106 // Move constructor: if m has a value, moves the value from m, leaving m | 
| 79 // still in a state where it has a value, but a moved-from one (the | 107 // still in a state where it has a value, but a moved-from one (the | 
| 80 // properties of which depends on T; the only general guarantee is that we | 108 // properties of which depends on T; the only general guarantee is that we | 
| 81 // can destroy m). | 109 // can destroy m). | 
| 82 Optional(Optional&& m) : has_value_(m.has_value_) { | 110 Optional(Optional&& m) : has_value_(m.has_value_) { | 
| 83 if (has_value_) | 111 if (has_value_) | 
| 84 new (&value_) T(std::move(m.value_)); | 112 new (&value_) T(std::move(m.value_)); | 
| 113 else | |
| 114 PoisonValue(); | |
| 85 } | 115 } | 
| 86 | 116 | 
| 87 ~Optional() { | 117 ~Optional() { | 
| 88 if (has_value_) | 118 if (has_value_) | 
| 89 value_.~T(); | 119 value_.~T(); | 
| 120 else | |
| 121 UnpoisonValue(); | |
| 90 } | 122 } | 
| 91 | 123 | 
| 92 // Copy assignment. Uses T's copy assignment if both sides have a value, T's | 124 // Copy assignment. Uses T's copy assignment if both sides have a value, T's | 
| 93 // copy constructor if only the right-hand side has a value. | 125 // copy constructor if only the right-hand side has a value. | 
| 94 Optional& operator=(const Optional& m) { | 126 Optional& operator=(const Optional& m) { | 
| 95 if (m.has_value_) { | 127 if (m.has_value_) { | 
| 96 if (has_value_) { | 128 if (has_value_) { | 
| 97 value_ = m.value_; // T's copy assignment. | 129 value_ = m.value_; // T's copy assignment. | 
| 98 } else { | 130 } else { | 
| 131 UnpoisonValue(); | |
| 99 new (&value_) T(m.value_); // T's copy constructor. | 132 new (&value_) T(m.value_); // T's copy constructor. | 
| 100 has_value_ = true; | 133 has_value_ = true; | 
| 101 } | 134 } | 
| 102 } else if (has_value_) { | 135 } else if (has_value_) { | 
| 103 value_.~T(); | 136 value_.~T(); | 
| 104 has_value_ = false; | 137 has_value_ = false; | 
| 138 PoisonValue(); | |
| 105 } | 139 } | 
| 106 return *this; | 140 return *this; | 
| 107 } | 141 } | 
| 108 | 142 | 
| 109 // Move assignment. Uses T's move assignment if both sides have a value, T's | 143 // Move assignment. Uses T's move assignment if both sides have a value, T's | 
| 110 // move constructor if only the right-hand side has a value. The state of m | 144 // move constructor if only the right-hand side has a value. The state of m | 
| 111 // after it's been moved from is as for the move constructor. | 145 // after it's been moved from is as for the move constructor. | 
| 112 Optional& operator=(Optional&& m) { | 146 Optional& operator=(Optional&& m) { | 
| 113 if (m.has_value_) { | 147 if (m.has_value_) { | 
| 114 if (has_value_) { | 148 if (has_value_) { | 
| 115 value_ = std::move(m.value_); // T's move assignment. | 149 value_ = std::move(m.value_); // T's move assignment. | 
| 116 } else { | 150 } else { | 
| 151 UnpoisonValue(); | |
| 117 new (&value_) T(std::move(m.value_)); // T's move constructor. | 152 new (&value_) T(std::move(m.value_)); // T's move constructor. | 
| 118 has_value_ = true; | 153 has_value_ = true; | 
| 119 } | 154 } | 
| 120 } else if (has_value_) { | 155 } else if (has_value_) { | 
| 121 value_.~T(); | 156 value_.~T(); | 
| 122 has_value_ = false; | 157 has_value_ = false; | 
| 158 PoisonValue(); | |
| 123 } | 159 } | 
| 124 return *this; | 160 return *this; | 
| 125 } | 161 } | 
| 126 | 162 | 
| 127 // Swap the values if both m1 and m2 have values; move the value if only one | 163 // Swap the values if both m1 and m2 have values; move the value if only one | 
| 128 // of them has one. | 164 // of them has one. | 
| 129 friend void swap(Optional& m1, Optional& m2) { | 165 friend void swap(Optional& m1, Optional& m2) { | 
| 130 if (m1.has_value_) { | 166 if (m1.has_value_) { | 
| 131 if (m2.has_value_) { | 167 if (m2.has_value_) { | 
| 132 // Both have values: swap. | 168 // Both have values: swap. | 
| 133 using std::swap; | 169 using std::swap; | 
| 134 swap(m1.value_, m2.value_); | 170 swap(m1.value_, m2.value_); | 
| 135 } else { | 171 } else { | 
| 136 // Only m1 has a value: move it to m2. | 172 // Only m1 has a value: move it to m2. | 
| 173 m2.UnpoisonValue(); | |
| 137 new (&m2.value_) T(std::move(m1.value_)); | 174 new (&m2.value_) T(std::move(m1.value_)); | 
| 138 m1.value_.~T(); // Destroy the moved-from value. | 175 m1.value_.~T(); // Destroy the moved-from value. | 
| 139 m1.has_value_ = false; | 176 m1.has_value_ = false; | 
| 140 m2.has_value_ = true; | 177 m2.has_value_ = true; | 
| 178 m1.PoisonValue(); | |
| 141 } | 179 } | 
| 142 } else if (m2.has_value_) { | 180 } else if (m2.has_value_) { | 
| 143 // Only m2 has a value: move it to m1. | 181 // Only m2 has a value: move it to m1. | 
| 182 m1.UnpoisonValue(); | |
| 144 new (&m1.value_) T(std::move(m2.value_)); | 183 new (&m1.value_) T(std::move(m2.value_)); | 
| 145 m2.value_.~T(); // Destroy the moved-from value. | 184 m2.value_.~T(); // Destroy the moved-from value. | 
| 146 m1.has_value_ = true; | 185 m1.has_value_ = true; | 
| 147 m2.has_value_ = false; | 186 m2.has_value_ = false; | 
| 187 m2.PoisonValue(); | |
| 148 } | 188 } | 
| 149 } | 189 } | 
| 150 | 190 | 
| 151 // Conversion to bool to test if we have a value. | 191 // Conversion to bool to test if we have a value. | 
| 152 explicit operator bool() const { return has_value_; } | 192 explicit operator bool() const { return has_value_; } | 
| 153 | 193 | 
| 154 // Dereferencing. Only allowed if we have a value. | 194 // Dereferencing. Only allowed if we have a value. | 
| 155 const T* operator->() const { | 195 const T* operator->() const { | 
| 156 RTC_DCHECK(has_value_); | 196 RTC_DCHECK(has_value_); | 
| 157 return &value_; | 197 return &value_; | 
| 158 } | 198 } | 
| 159 T* operator->() { | 199 T* operator->() { | 
| 160 RTC_DCHECK(has_value_); | 200 RTC_DCHECK(has_value_); | 
| 161 return &value_; | 201 return &value_; | 
| 162 } | 202 } | 
| 163 const T& operator*() const { | 203 const T& operator*() const { | 
| 164 RTC_DCHECK(has_value_); | 204 RTC_DCHECK(has_value_); | 
| 165 return value_; | 205 return value_; | 
| 166 } | 206 } | 
| 167 T& operator*() { | 207 T& operator*() { | 
| 168 RTC_DCHECK(has_value_); | 208 RTC_DCHECK(has_value_); | 
| 169 return value_; | 209 return value_; | 
| 170 } | 210 } | 
| 171 | 211 | 
| 172 // Dereference with a default value in case we don't have a value. | 212 // Dereference with a default value in case we don't have a value. | 
| 173 const T& value_or(const T& default_val) const { | 213 const T& value_or(const T& default_val) const { | 
| 174 return has_value_ ? value_ : default_val; | 214 if (has_value_) { | 
| 215 // This no-op call prevents the optimizer from going this way and reading | |
| 216 // value_ if !has_value_ (but only if FunctionThatDoesNothing is not | |
| 217 // completely inlined; see its declaration.). | |
| 218 return *internal::FunctionThatDoesNothing(&value_); | |
| 219 } else { | |
| 
tommi
2016/09/03 15:00:50
nit: else not necessary
 
kwiberg-webrtc
2016/09/03 16:05:36
Done.
 | |
| 220 return default_val; | |
| 221 } | |
| 175 } | 222 } | 
| 176 | 223 | 
| 177 // Equality tests. Two Optionals are equal if they contain equivalent values, | 224 // Equality tests. Two Optionals are equal if they contain equivalent values, | 
| 178 // or | 225 // or | 
| 179 // if they're both empty. | 226 // if they're both empty. | 
| 180 friend bool operator==(const Optional& m1, const Optional& m2) { | 227 friend bool operator==(const Optional& m1, const Optional& m2) { | 
| 181 return m1.has_value_ && m2.has_value_ ? m1.value_ == m2.value_ | 228 return m1.has_value_ && m2.has_value_ ? m1.value_ == m2.value_ | 
| 182 : m1.has_value_ == m2.has_value_; | 229 : m1.has_value_ == m2.has_value_; | 
| 183 } | 230 } | 
| 184 friend bool operator!=(const Optional& m1, const Optional& m2) { | 231 friend bool operator!=(const Optional& m1, const Optional& m2) { | 
| 185 return m1.has_value_ && m2.has_value_ ? m1.value_ != m2.value_ | 232 return m1.has_value_ && m2.has_value_ ? m1.value_ != m2.value_ | 
| 186 : m1.has_value_ != m2.has_value_; | 233 : m1.has_value_ != m2.has_value_; | 
| 187 } | 234 } | 
| 188 | 235 | 
| 189 private: | 236 private: | 
| 237 // Tell sanitizers that value_ shouldn't be touched. | |
| 238 void PoisonValue() { | |
| 239 rtc::AsanPoison(rtc::MakeArrayView(&value_, 1)); | |
| 240 rtc::MsanMarkUninitialized(rtc::MakeArrayView(&value_, 1)); | |
| 241 } | |
| 242 | |
| 243 // Tell sanitizers that value_ is OK to touch again. | |
| 244 void UnpoisonValue() { | |
| 245 rtc::AsanUnpoison(rtc::MakeArrayView(&value_, 1)); | |
| 246 } | |
| 247 | |
| 190 bool has_value_; // True iff value_ contains a live value. | 248 bool has_value_; // True iff value_ contains a live value. | 
| 191 union { | 249 union { | 
| 192 // empty_ exists only to make it possible to initialize the union, even when | 250 // empty_ exists only to make it possible to initialize the union, even when | 
| 193 // it doesn't contain any data. If the union goes uninitialized, it may | 251 // it doesn't contain any data. If the union goes uninitialized, it may | 
| 194 // trigger compiler warnings. | 252 // trigger compiler warnings. | 
| 195 char empty_; | 253 char empty_; | 
| 196 // By placing value_ in a union, we get to manage its construction and | 254 // By placing value_ in a union, we get to manage its construction and | 
| 197 // destruction manually: the Optional constructors won't automatically | 255 // destruction manually: the Optional constructors won't automatically | 
| 198 // construct it, and the Optional destructor won't automatically destroy | 256 // construct it, and the Optional destructor won't automatically destroy | 
| 199 // it. Basically, this just allocates a properly sized and aligned block of | 257 // it. Basically, this just allocates a properly sized and aligned block of | 
| 200 // memory in which we can manually put a T with placement new. | 258 // memory in which we can manually put a T with placement new. | 
| 201 T value_; | 259 T value_; | 
| 202 }; | 260 }; | 
| 203 }; | 261 }; | 
| 204 | 262 | 
| 205 } // namespace rtc | 263 } // namespace rtc | 
| 206 | 264 | 
| 207 #endif // WEBRTC_BASE_OPTIONAL_H_ | 265 #endif // WEBRTC_BASE_OPTIONAL_H_ | 
| OLD | NEW |