exception_safety_testing.h (38348B)
1 // Copyright 2017 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Utilities for testing exception-safety 16 17 #ifndef ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_ 18 #define ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_ 19 20 #include "absl/base/config.h" 21 22 #ifdef ABSL_HAVE_EXCEPTIONS 23 24 #include <cstddef> 25 #include <cstdint> 26 #include <functional> 27 #include <initializer_list> 28 #include <iosfwd> 29 #include <string> 30 #include <tuple> 31 #include <unordered_map> 32 33 #include "gtest/gtest.h" 34 #include "absl/base/internal/pretty_function.h" 35 #include "absl/memory/memory.h" 36 #include "absl/meta/type_traits.h" 37 #include "absl/strings/string_view.h" 38 #include "absl/strings/substitute.h" 39 #include "absl/utility/utility.h" 40 41 namespace testing { 42 43 enum class TypeSpec; 44 enum class AllocSpec; 45 46 constexpr TypeSpec operator|(TypeSpec a, TypeSpec b) { 47 using T = absl::underlying_type_t<TypeSpec>; 48 return static_cast<TypeSpec>(static_cast<T>(a) | static_cast<T>(b)); 49 } 50 51 constexpr TypeSpec operator&(TypeSpec a, TypeSpec b) { 52 using T = absl::underlying_type_t<TypeSpec>; 53 return static_cast<TypeSpec>(static_cast<T>(a) & static_cast<T>(b)); 54 } 55 56 constexpr AllocSpec operator|(AllocSpec a, AllocSpec b) { 57 using T = absl::underlying_type_t<AllocSpec>; 58 return static_cast<AllocSpec>(static_cast<T>(a) | static_cast<T>(b)); 59 } 60 61 constexpr AllocSpec operator&(AllocSpec a, AllocSpec b) { 62 using T = absl::underlying_type_t<AllocSpec>; 63 return static_cast<AllocSpec>(static_cast<T>(a) & static_cast<T>(b)); 64 } 65 66 namespace exceptions_internal { 67 68 std::string GetSpecString(TypeSpec); 69 std::string GetSpecString(AllocSpec); 70 71 struct NoThrowTag {}; 72 struct StrongGuaranteeTagType {}; 73 74 // A simple exception class. We throw this so that test code can catch 75 // exceptions specifically thrown by ThrowingValue. 76 class TestException { 77 public: 78 explicit TestException(absl::string_view msg) : msg_(msg) {} 79 virtual ~TestException() {} 80 virtual const char* what() const noexcept { return msg_.c_str(); } 81 82 private: 83 std::string msg_; 84 }; 85 86 // TestBadAllocException exists because allocation functions must throw an 87 // exception which can be caught by a handler of std::bad_alloc. We use a child 88 // class of std::bad_alloc so we can customise the error message, and also 89 // derive from TestException so we don't accidentally end up catching an actual 90 // bad_alloc exception in TestExceptionSafety. 91 class TestBadAllocException : public std::bad_alloc, public TestException { 92 public: 93 explicit TestBadAllocException(absl::string_view msg) : TestException(msg) {} 94 using TestException::what; 95 }; 96 97 extern int countdown; 98 99 // Allows the countdown variable to be set manually (defaulting to the initial 100 // value of 0) 101 inline void SetCountdown(int i = 0) { countdown = i; } 102 // Sets the countdown to the terminal value -1 103 inline void UnsetCountdown() { SetCountdown(-1); } 104 105 void MaybeThrow(absl::string_view msg, bool throw_bad_alloc = false); 106 107 testing::AssertionResult FailureMessage(const TestException& e, 108 int countdown) noexcept; 109 110 struct TrackedAddress { 111 bool is_alive; 112 std::string description; 113 }; 114 115 // Inspects the constructions and destructions of anything inheriting from 116 // TrackedObject. This allows us to safely "leak" TrackedObjects, as 117 // ConstructorTracker will destroy everything left over in its destructor. 118 class ConstructorTracker { 119 public: 120 explicit ConstructorTracker(int count) : countdown_(count) { 121 assert(current_tracker_instance_ == nullptr); 122 current_tracker_instance_ = this; 123 } 124 125 ~ConstructorTracker() { 126 assert(current_tracker_instance_ == this); 127 current_tracker_instance_ = nullptr; 128 129 for (auto& it : address_map_) { 130 void* address = it.first; 131 TrackedAddress& tracked_address = it.second; 132 if (tracked_address.is_alive) { 133 ADD_FAILURE() << ErrorMessage(address, tracked_address.description, 134 countdown_, "Object was not destroyed."); 135 } 136 } 137 } 138 139 static void ObjectConstructed(void* address, std::string description) { 140 if (!CurrentlyTracking()) return; 141 142 TrackedAddress& tracked_address = 143 current_tracker_instance_->address_map_[address]; 144 if (tracked_address.is_alive) { 145 ADD_FAILURE() << ErrorMessage( 146 address, tracked_address.description, 147 current_tracker_instance_->countdown_, 148 "Object was re-constructed. Current object was constructed by " + 149 description); 150 } 151 tracked_address = {true, std::move(description)}; 152 } 153 154 static void ObjectDestructed(void* address) { 155 if (!CurrentlyTracking()) return; 156 157 auto it = current_tracker_instance_->address_map_.find(address); 158 // Not tracked. Ignore. 159 if (it == current_tracker_instance_->address_map_.end()) return; 160 161 TrackedAddress& tracked_address = it->second; 162 if (!tracked_address.is_alive) { 163 ADD_FAILURE() << ErrorMessage(address, tracked_address.description, 164 current_tracker_instance_->countdown_, 165 "Object was re-destroyed."); 166 } 167 tracked_address.is_alive = false; 168 } 169 170 private: 171 static bool CurrentlyTracking() { 172 return current_tracker_instance_ != nullptr; 173 } 174 175 static std::string ErrorMessage(void* address, 176 const std::string& address_description, 177 int countdown, 178 const std::string& error_description) { 179 return absl::Substitute( 180 "With coundtown at $0:\n" 181 " $1\n" 182 " Object originally constructed by $2\n" 183 " Object address: $3\n", 184 countdown, error_description, address_description, address); 185 } 186 187 std::unordered_map<void*, TrackedAddress> address_map_; 188 int countdown_; 189 190 static ConstructorTracker* current_tracker_instance_; 191 }; 192 193 class TrackedObject { 194 public: 195 TrackedObject(const TrackedObject&) = delete; 196 TrackedObject(TrackedObject&&) = delete; 197 198 protected: 199 explicit TrackedObject(std::string description) { 200 ConstructorTracker::ObjectConstructed(this, std::move(description)); 201 } 202 203 ~TrackedObject() noexcept { ConstructorTracker::ObjectDestructed(this); } 204 }; 205 } // namespace exceptions_internal 206 207 extern exceptions_internal::NoThrowTag nothrow_ctor; 208 209 extern exceptions_internal::StrongGuaranteeTagType strong_guarantee; 210 211 // A test class which is convertible to bool. The conversion can be 212 // instrumented to throw at a controlled time. 213 class ThrowingBool { 214 public: 215 ThrowingBool(bool b) noexcept : b_(b) {} // NOLINT(runtime/explicit) 216 operator bool() const { // NOLINT 217 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 218 return b_; 219 } 220 221 private: 222 bool b_; 223 }; 224 225 /* 226 * Configuration enum for the ThrowingValue type that defines behavior for the 227 * lifetime of the instance. Use testing::nothrow_ctor to prevent the integer 228 * constructor from throwing. 229 * 230 * kEverythingThrows: Every operation can throw an exception 231 * kNoThrowCopy: Copy construction and copy assignment will not throw 232 * kNoThrowMove: Move construction and move assignment will not throw 233 * kNoThrowNew: Overloaded operators new and new[] will not throw 234 */ 235 enum class TypeSpec { 236 kEverythingThrows = 0, 237 kNoThrowCopy = 1, 238 kNoThrowMove = 1 << 1, 239 kNoThrowNew = 1 << 2, 240 }; 241 242 /* 243 * A testing class instrumented to throw an exception at a controlled time. 244 * 245 * ThrowingValue implements a slightly relaxed version of the Regular concept -- 246 * that is it's a value type with the expected semantics. It also implements 247 * arithmetic operations. It doesn't implement member and pointer operators 248 * like operator-> or operator[]. 249 * 250 * ThrowingValue can be instrumented to have certain operations be noexcept by 251 * using compile-time bitfield template arguments. That is, to make an 252 * ThrowingValue which has noexcept move construction/assignment and noexcept 253 * copy construction/assignment, use the following: 254 * ThrowingValue<testing::kNoThrowMove | testing::kNoThrowCopy> my_thrwr{val}; 255 */ 256 template <TypeSpec Spec = TypeSpec::kEverythingThrows> 257 class ThrowingValue : private exceptions_internal::TrackedObject { 258 static constexpr bool IsSpecified(TypeSpec spec) { 259 return static_cast<bool>(Spec & spec); 260 } 261 262 static constexpr int kDefaultValue = 0; 263 static constexpr int kBadValue = 938550620; 264 265 public: 266 ThrowingValue() : TrackedObject(GetInstanceString(kDefaultValue)) { 267 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 268 dummy_ = kDefaultValue; 269 } 270 271 ThrowingValue(const ThrowingValue& other) noexcept( 272 IsSpecified(TypeSpec::kNoThrowCopy)) 273 : TrackedObject(GetInstanceString(other.dummy_)) { 274 if (!IsSpecified(TypeSpec::kNoThrowCopy)) { 275 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 276 } 277 dummy_ = other.dummy_; 278 } 279 280 ThrowingValue(ThrowingValue&& other) noexcept( 281 IsSpecified(TypeSpec::kNoThrowMove)) 282 : TrackedObject(GetInstanceString(other.dummy_)) { 283 if (!IsSpecified(TypeSpec::kNoThrowMove)) { 284 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 285 } 286 dummy_ = other.dummy_; 287 } 288 289 explicit ThrowingValue(int i) : TrackedObject(GetInstanceString(i)) { 290 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 291 dummy_ = i; 292 } 293 294 ThrowingValue(int i, exceptions_internal::NoThrowTag) noexcept 295 : TrackedObject(GetInstanceString(i)), dummy_(i) {} 296 297 // absl expects nothrow destructors 298 ~ThrowingValue() noexcept = default; 299 300 ThrowingValue& operator=(const ThrowingValue& other) noexcept( 301 IsSpecified(TypeSpec::kNoThrowCopy)) { 302 dummy_ = kBadValue; 303 if (!IsSpecified(TypeSpec::kNoThrowCopy)) { 304 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 305 } 306 dummy_ = other.dummy_; 307 return *this; 308 } 309 310 ThrowingValue& operator=(ThrowingValue&& other) noexcept( 311 IsSpecified(TypeSpec::kNoThrowMove)) { 312 dummy_ = kBadValue; 313 if (!IsSpecified(TypeSpec::kNoThrowMove)) { 314 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 315 } 316 dummy_ = other.dummy_; 317 return *this; 318 } 319 320 // Arithmetic Operators 321 ThrowingValue operator+(const ThrowingValue& other) const { 322 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 323 return ThrowingValue(dummy_ + other.dummy_, nothrow_ctor); 324 } 325 326 ThrowingValue operator+() const { 327 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 328 return ThrowingValue(dummy_, nothrow_ctor); 329 } 330 331 ThrowingValue operator-(const ThrowingValue& other) const { 332 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 333 return ThrowingValue(dummy_ - other.dummy_, nothrow_ctor); 334 } 335 336 ThrowingValue operator-() const { 337 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 338 return ThrowingValue(-dummy_, nothrow_ctor); 339 } 340 341 ThrowingValue& operator++() { 342 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 343 ++dummy_; 344 return *this; 345 } 346 347 ThrowingValue operator++(int) { 348 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 349 auto out = ThrowingValue(dummy_, nothrow_ctor); 350 ++dummy_; 351 return out; 352 } 353 354 ThrowingValue& operator--() { 355 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 356 --dummy_; 357 return *this; 358 } 359 360 ThrowingValue operator--(int) { 361 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 362 auto out = ThrowingValue(dummy_, nothrow_ctor); 363 --dummy_; 364 return out; 365 } 366 367 ThrowingValue operator*(const ThrowingValue& other) const { 368 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 369 return ThrowingValue(dummy_ * other.dummy_, nothrow_ctor); 370 } 371 372 ThrowingValue operator/(const ThrowingValue& other) const { 373 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 374 return ThrowingValue(dummy_ / other.dummy_, nothrow_ctor); 375 } 376 377 ThrowingValue operator%(const ThrowingValue& other) const { 378 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 379 return ThrowingValue(dummy_ % other.dummy_, nothrow_ctor); 380 } 381 382 ThrowingValue operator<<(int shift) const { 383 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 384 return ThrowingValue(dummy_ << shift, nothrow_ctor); 385 } 386 387 ThrowingValue operator>>(int shift) const { 388 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 389 return ThrowingValue(dummy_ >> shift, nothrow_ctor); 390 } 391 392 // Comparison Operators 393 // NOTE: We use `ThrowingBool` instead of `bool` because most STL 394 // types/containers requires T to be convertible to bool. 395 friend ThrowingBool operator==(const ThrowingValue& a, 396 const ThrowingValue& b) { 397 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 398 return a.dummy_ == b.dummy_; 399 } 400 friend ThrowingBool operator!=(const ThrowingValue& a, 401 const ThrowingValue& b) { 402 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 403 return a.dummy_ != b.dummy_; 404 } 405 friend ThrowingBool operator<(const ThrowingValue& a, 406 const ThrowingValue& b) { 407 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 408 return a.dummy_ < b.dummy_; 409 } 410 friend ThrowingBool operator<=(const ThrowingValue& a, 411 const ThrowingValue& b) { 412 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 413 return a.dummy_ <= b.dummy_; 414 } 415 friend ThrowingBool operator>(const ThrowingValue& a, 416 const ThrowingValue& b) { 417 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 418 return a.dummy_ > b.dummy_; 419 } 420 friend ThrowingBool operator>=(const ThrowingValue& a, 421 const ThrowingValue& b) { 422 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 423 return a.dummy_ >= b.dummy_; 424 } 425 426 // Logical Operators 427 ThrowingBool operator!() const { 428 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 429 return !dummy_; 430 } 431 432 ThrowingBool operator&&(const ThrowingValue& other) const { 433 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 434 return dummy_ && other.dummy_; 435 } 436 437 ThrowingBool operator||(const ThrowingValue& other) const { 438 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 439 return dummy_ || other.dummy_; 440 } 441 442 // Bitwise Logical Operators 443 ThrowingValue operator~() const { 444 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 445 return ThrowingValue(~dummy_, nothrow_ctor); 446 } 447 448 ThrowingValue operator&(const ThrowingValue& other) const { 449 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 450 return ThrowingValue(dummy_ & other.dummy_, nothrow_ctor); 451 } 452 453 ThrowingValue operator|(const ThrowingValue& other) const { 454 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 455 return ThrowingValue(dummy_ | other.dummy_, nothrow_ctor); 456 } 457 458 ThrowingValue operator^(const ThrowingValue& other) const { 459 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 460 return ThrowingValue(dummy_ ^ other.dummy_, nothrow_ctor); 461 } 462 463 // Compound Assignment operators 464 ThrowingValue& operator+=(const ThrowingValue& other) { 465 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 466 dummy_ += other.dummy_; 467 return *this; 468 } 469 470 ThrowingValue& operator-=(const ThrowingValue& other) { 471 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 472 dummy_ -= other.dummy_; 473 return *this; 474 } 475 476 ThrowingValue& operator*=(const ThrowingValue& other) { 477 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 478 dummy_ *= other.dummy_; 479 return *this; 480 } 481 482 ThrowingValue& operator/=(const ThrowingValue& other) { 483 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 484 dummy_ /= other.dummy_; 485 return *this; 486 } 487 488 ThrowingValue& operator%=(const ThrowingValue& other) { 489 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 490 dummy_ %= other.dummy_; 491 return *this; 492 } 493 494 ThrowingValue& operator&=(const ThrowingValue& other) { 495 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 496 dummy_ &= other.dummy_; 497 return *this; 498 } 499 500 ThrowingValue& operator|=(const ThrowingValue& other) { 501 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 502 dummy_ |= other.dummy_; 503 return *this; 504 } 505 506 ThrowingValue& operator^=(const ThrowingValue& other) { 507 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 508 dummy_ ^= other.dummy_; 509 return *this; 510 } 511 512 ThrowingValue& operator<<=(int shift) { 513 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 514 dummy_ <<= shift; 515 return *this; 516 } 517 518 ThrowingValue& operator>>=(int shift) { 519 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 520 dummy_ >>= shift; 521 return *this; 522 } 523 524 // Pointer operators 525 void operator&() const = delete; // NOLINT(runtime/operator) 526 527 // Stream operators 528 friend std::ostream& operator<<(std::ostream& os, const ThrowingValue& tv) { 529 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 530 return os << GetInstanceString(tv.dummy_); 531 } 532 533 friend std::istream& operator>>(std::istream& is, const ThrowingValue&) { 534 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 535 return is; 536 } 537 538 // Memory management operators 539 static void* operator new(size_t s) noexcept( 540 IsSpecified(TypeSpec::kNoThrowNew)) { 541 if (!IsSpecified(TypeSpec::kNoThrowNew)) { 542 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true); 543 } 544 return ::operator new(s); 545 } 546 547 static void* operator new[](size_t s) noexcept( 548 IsSpecified(TypeSpec::kNoThrowNew)) { 549 if (!IsSpecified(TypeSpec::kNoThrowNew)) { 550 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true); 551 } 552 return ::operator new[](s); 553 } 554 555 template <typename... Args> 556 static void* operator new(size_t s, Args&&... args) noexcept( 557 IsSpecified(TypeSpec::kNoThrowNew)) { 558 if (!IsSpecified(TypeSpec::kNoThrowNew)) { 559 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true); 560 } 561 return ::operator new(s, std::forward<Args>(args)...); 562 } 563 564 template <typename... Args> 565 static void* operator new[](size_t s, Args&&... args) noexcept( 566 IsSpecified(TypeSpec::kNoThrowNew)) { 567 if (!IsSpecified(TypeSpec::kNoThrowNew)) { 568 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true); 569 } 570 return ::operator new[](s, std::forward<Args>(args)...); 571 } 572 573 // Abseil doesn't support throwing overloaded operator delete. These are 574 // provided so a throwing operator-new can clean up after itself. 575 void operator delete(void* p) noexcept { ::operator delete(p); } 576 577 template <typename... Args> 578 void operator delete(void* p, Args&&... args) noexcept { 579 ::operator delete(p, std::forward<Args>(args)...); 580 } 581 582 void operator delete[](void* p) noexcept { return ::operator delete[](p); } 583 584 template <typename... Args> 585 void operator delete[](void* p, Args&&... args) noexcept { 586 return ::operator delete[](p, std::forward<Args>(args)...); 587 } 588 589 // Non-standard access to the actual contained value. No need for this to 590 // throw. 591 int& Get() noexcept { return dummy_; } 592 const int& Get() const noexcept { return dummy_; } 593 594 private: 595 static std::string GetInstanceString(int dummy) { 596 return absl::StrCat("ThrowingValue<", 597 exceptions_internal::GetSpecString(Spec), ">(", dummy, 598 ")"); 599 } 600 601 int dummy_; 602 }; 603 // While not having to do with exceptions, explicitly delete comma operator, to 604 // make sure we don't use it on user-supplied types. 605 template <TypeSpec Spec, typename T> 606 void operator,(const ThrowingValue<Spec>&, T&&) = delete; 607 template <TypeSpec Spec, typename T> 608 void operator,(T&&, const ThrowingValue<Spec>&) = delete; 609 610 /* 611 * Configuration enum for the ThrowingAllocator type that defines behavior for 612 * the lifetime of the instance. 613 * 614 * kEverythingThrows: Calls to the member functions may throw 615 * kNoThrowAllocate: Calls to the member functions will not throw 616 */ 617 enum class AllocSpec { 618 kEverythingThrows = 0, 619 kNoThrowAllocate = 1, 620 }; 621 622 /* 623 * An allocator type which is instrumented to throw at a controlled time, or not 624 * to throw, using AllocSpec. The supported settings are the default of every 625 * function which is allowed to throw in a conforming allocator possibly 626 * throwing, or nothing throws, in line with the ABSL_ALLOCATOR_THROWS 627 * configuration macro. 628 */ 629 template <typename T, AllocSpec Spec = AllocSpec::kEverythingThrows> 630 class ThrowingAllocator : private exceptions_internal::TrackedObject { 631 static constexpr bool IsSpecified(AllocSpec spec) { 632 return static_cast<bool>(Spec & spec); 633 } 634 635 public: 636 using pointer = T*; 637 using const_pointer = const T*; 638 using reference = T&; 639 using const_reference = const T&; 640 using void_pointer = void*; 641 using const_void_pointer = const void*; 642 using value_type = T; 643 using size_type = size_t; 644 using difference_type = ptrdiff_t; 645 646 using is_nothrow = 647 std::integral_constant<bool, Spec == AllocSpec::kNoThrowAllocate>; 648 using propagate_on_container_copy_assignment = std::true_type; 649 using propagate_on_container_move_assignment = std::true_type; 650 using propagate_on_container_swap = std::true_type; 651 using is_always_equal = std::false_type; 652 653 ThrowingAllocator() : TrackedObject(GetInstanceString(next_id_)) { 654 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); 655 dummy_ = std::make_shared<const int>(next_id_++); 656 } 657 658 template <typename U> 659 ThrowingAllocator(const ThrowingAllocator<U, Spec>& other) noexcept // NOLINT 660 : TrackedObject(GetInstanceString(*other.State())), 661 dummy_(other.State()) {} 662 663 // According to C++11 standard [17.6.3.5], Table 28, the move/copy ctors of 664 // allocator shall not exit via an exception, thus they are marked noexcept. 665 ThrowingAllocator(const ThrowingAllocator& other) noexcept 666 : TrackedObject(GetInstanceString(*other.State())), 667 dummy_(other.State()) {} 668 669 template <typename U> 670 ThrowingAllocator(ThrowingAllocator<U, Spec>&& other) noexcept // NOLINT 671 : TrackedObject(GetInstanceString(*other.State())), 672 dummy_(std::move(other.State())) {} 673 674 ThrowingAllocator(ThrowingAllocator&& other) noexcept 675 : TrackedObject(GetInstanceString(*other.State())), 676 dummy_(std::move(other.State())) {} 677 678 ~ThrowingAllocator() noexcept = default; 679 680 ThrowingAllocator& operator=(const ThrowingAllocator& other) noexcept { 681 dummy_ = other.State(); 682 return *this; 683 } 684 685 template <typename U> 686 ThrowingAllocator& operator=( 687 const ThrowingAllocator<U, Spec>& other) noexcept { 688 dummy_ = other.State(); 689 return *this; 690 } 691 692 template <typename U> 693 ThrowingAllocator& operator=(ThrowingAllocator<U, Spec>&& other) noexcept { 694 dummy_ = std::move(other.State()); 695 return *this; 696 } 697 698 template <typename U> 699 struct rebind { 700 using other = ThrowingAllocator<U, Spec>; 701 }; 702 703 pointer allocate(size_type n) noexcept( 704 IsSpecified(AllocSpec::kNoThrowAllocate)) { 705 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION); 706 return static_cast<pointer>(::operator new(n * sizeof(T))); 707 } 708 709 pointer allocate(size_type n, const_void_pointer) noexcept( 710 IsSpecified(AllocSpec::kNoThrowAllocate)) { 711 return allocate(n); 712 } 713 714 void deallocate(pointer ptr, size_type) noexcept { 715 ReadState(); 716 ::operator delete(static_cast<void*>(ptr)); 717 } 718 719 template <typename U, typename... Args> 720 void construct(U* ptr, Args&&... args) noexcept( 721 IsSpecified(AllocSpec::kNoThrowAllocate)) { 722 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION); 723 ::new (static_cast<void*>(ptr)) U(std::forward<Args>(args)...); 724 } 725 726 template <typename U> 727 void destroy(U* p) noexcept { 728 ReadState(); 729 p->~U(); 730 } 731 732 size_type max_size() const noexcept { 733 return (std::numeric_limits<difference_type>::max)() / sizeof(value_type); 734 } 735 736 ThrowingAllocator select_on_container_copy_construction() noexcept( 737 IsSpecified(AllocSpec::kNoThrowAllocate)) { 738 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION); 739 return *this; 740 } 741 742 template <typename U> 743 bool operator==(const ThrowingAllocator<U, Spec>& other) const noexcept { 744 return dummy_ == other.dummy_; 745 } 746 747 template <typename U> 748 bool operator!=(const ThrowingAllocator<U, Spec>& other) const noexcept { 749 return dummy_ != other.dummy_; 750 } 751 752 template <typename, AllocSpec> 753 friend class ThrowingAllocator; 754 755 private: 756 static std::string GetInstanceString(int dummy) { 757 return absl::StrCat("ThrowingAllocator<", 758 exceptions_internal::GetSpecString(Spec), ">(", dummy, 759 ")"); 760 } 761 762 const std::shared_ptr<const int>& State() const { return dummy_; } 763 std::shared_ptr<const int>& State() { return dummy_; } 764 765 void ReadState() { 766 // we know that this will never be true, but the compiler doesn't, so this 767 // should safely force a read of the value. 768 if (*dummy_ < 0) std::abort(); 769 } 770 771 void ReadStateAndMaybeThrow(absl::string_view msg) const { 772 if (!IsSpecified(AllocSpec::kNoThrowAllocate)) { 773 exceptions_internal::MaybeThrow( 774 absl::Substitute("Allocator id $0 threw from $1", *dummy_, msg)); 775 } 776 } 777 778 static int next_id_; 779 std::shared_ptr<const int> dummy_; 780 }; 781 782 template <typename T, AllocSpec Spec> 783 int ThrowingAllocator<T, Spec>::next_id_ = 0; 784 785 // Tests for resource leaks by attempting to construct a T using args repeatedly 786 // until successful, using the countdown method. Side effects can then be 787 // tested for resource leaks. 788 template <typename T, typename... Args> 789 void TestThrowingCtor(Args&&... args) { 790 struct Cleanup { 791 ~Cleanup() { exceptions_internal::UnsetCountdown(); } 792 } c; 793 for (int count = 0;; ++count) { 794 exceptions_internal::ConstructorTracker ct(count); 795 exceptions_internal::SetCountdown(count); 796 try { 797 T temp(std::forward<Args>(args)...); 798 static_cast<void>(temp); 799 break; 800 } catch (const exceptions_internal::TestException&) { 801 } 802 } 803 } 804 805 // Tests the nothrow guarantee of the provided nullary operation. If the an 806 // exception is thrown, the result will be AssertionFailure(). Otherwise, it 807 // will be AssertionSuccess(). 808 template <typename Operation> 809 testing::AssertionResult TestNothrowOp(const Operation& operation) { 810 struct Cleanup { 811 Cleanup() { exceptions_internal::SetCountdown(); } 812 ~Cleanup() { exceptions_internal::UnsetCountdown(); } 813 } c; 814 try { 815 operation(); 816 return testing::AssertionSuccess(); 817 } catch (const exceptions_internal::TestException&) { 818 return testing::AssertionFailure() 819 << "TestException thrown during call to operation() when nothrow " 820 "guarantee was expected."; 821 } catch (...) { 822 return testing::AssertionFailure() 823 << "Unknown exception thrown during call to operation() when " 824 "nothrow guarantee was expected."; 825 } 826 } 827 828 namespace exceptions_internal { 829 830 // Dummy struct for ExceptionSafetyTestBuilder<> partial state. 831 struct UninitializedT {}; 832 833 template <typename T> 834 class DefaultFactory { 835 public: 836 explicit DefaultFactory(const T& t) : t_(t) {} 837 std::unique_ptr<T> operator()() const { return absl::make_unique<T>(t_); } 838 839 private: 840 T t_; 841 }; 842 843 template <size_t LazyContractsCount, typename LazyFactory, 844 typename LazyOperation> 845 using EnableIfTestable = typename absl::enable_if_t< 846 LazyContractsCount != 0 && 847 !std::is_same<LazyFactory, UninitializedT>::value && 848 !std::is_same<LazyOperation, UninitializedT>::value>; 849 850 template <typename Factory = UninitializedT, 851 typename Operation = UninitializedT, typename... Contracts> 852 class ExceptionSafetyTestBuilder; 853 854 } // namespace exceptions_internal 855 856 /* 857 * Constructs an empty ExceptionSafetyTestBuilder. All 858 * ExceptionSafetyTestBuilder objects are immutable and all With[thing] mutation 859 * methods return new instances of ExceptionSafetyTestBuilder. 860 * 861 * In order to test a T for exception safety, a factory for that T, a testable 862 * operation, and at least one contract callback returning an assertion 863 * result must be applied using the respective methods. 864 */ 865 exceptions_internal::ExceptionSafetyTestBuilder<> MakeExceptionSafetyTester(); 866 867 namespace exceptions_internal { 868 template <typename T> 869 struct IsUniquePtr : std::false_type {}; 870 871 template <typename T, typename D> 872 struct IsUniquePtr<std::unique_ptr<T, D>> : std::true_type {}; 873 874 template <typename Factory> 875 struct FactoryPtrTypeHelper { 876 using type = decltype(std::declval<const Factory&>()()); 877 878 static_assert(IsUniquePtr<type>::value, "Factories must return a unique_ptr"); 879 }; 880 881 template <typename Factory> 882 using FactoryPtrType = typename FactoryPtrTypeHelper<Factory>::type; 883 884 template <typename Factory> 885 using FactoryElementType = typename FactoryPtrType<Factory>::element_type; 886 887 template <typename T> 888 class ExceptionSafetyTest { 889 using Factory = std::function<std::unique_ptr<T>()>; 890 using Operation = std::function<void(T*)>; 891 using Contract = std::function<AssertionResult(T*)>; 892 893 public: 894 template <typename... Contracts> 895 explicit ExceptionSafetyTest(const Factory& f, const Operation& op, 896 const Contracts&... contracts) 897 : factory_(f), operation_(op), contracts_{WrapContract(contracts)...} {} 898 899 AssertionResult Test() const { 900 for (int count = 0;; ++count) { 901 exceptions_internal::ConstructorTracker ct(count); 902 903 for (const auto& contract : contracts_) { 904 auto t_ptr = factory_(); 905 try { 906 SetCountdown(count); 907 operation_(t_ptr.get()); 908 // Unset for the case that the operation throws no exceptions, which 909 // would leave the countdown set and break the *next* exception safety 910 // test after this one. 911 UnsetCountdown(); 912 return AssertionSuccess(); 913 } catch (const exceptions_internal::TestException& e) { 914 if (!contract(t_ptr.get())) { 915 return AssertionFailure() << e.what() << " failed contract check"; 916 } 917 } 918 } 919 } 920 } 921 922 private: 923 template <typename ContractFn> 924 Contract WrapContract(const ContractFn& contract) { 925 return [contract](T* t_ptr) { return AssertionResult(contract(t_ptr)); }; 926 } 927 928 Contract WrapContract(StrongGuaranteeTagType) { 929 return [this](T* t_ptr) { return AssertionResult(*factory_() == *t_ptr); }; 930 } 931 932 Factory factory_; 933 Operation operation_; 934 std::vector<Contract> contracts_; 935 }; 936 937 /* 938 * Builds a tester object that tests if performing a operation on a T follows 939 * exception safety guarantees. Verification is done via contract assertion 940 * callbacks applied to T instances post-throw. 941 * 942 * Template parameters for ExceptionSafetyTestBuilder: 943 * 944 * - Factory: The factory object (passed in via tester.WithFactory(...) or 945 * tester.WithInitialValue(...)) must be invocable with the signature 946 * `std::unique_ptr<T> operator()() const` where T is the type being tested. 947 * It is used for reliably creating identical T instances to test on. 948 * 949 * - Operation: The operation object (passed in via tester.WithOperation(...) 950 * or tester.Test(...)) must be invocable with the signature 951 * `void operator()(T*) const` where T is the type being tested. It is used 952 * for performing steps on a T instance that may throw and that need to be 953 * checked for exception safety. Each call to the operation will receive a 954 * fresh T instance so it's free to modify and destroy the T instances as it 955 * pleases. 956 * 957 * - Contracts...: The contract assertion callback objects (passed in via 958 * tester.WithContracts(...)) must be invocable with the signature 959 * `testing::AssertionResult operator()(T*) const` where T is the type being 960 * tested. Contract assertion callbacks are provided T instances post-throw. 961 * They must return testing::AssertionSuccess when the type contracts of the 962 * provided T instance hold. If the type contracts of the T instance do not 963 * hold, they must return testing::AssertionFailure. Execution order of 964 * Contracts... is unspecified. They will each individually get a fresh T 965 * instance so they are free to modify and destroy the T instances as they 966 * please. 967 */ 968 template <typename Factory, typename Operation, typename... Contracts> 969 class ExceptionSafetyTestBuilder { 970 public: 971 /* 972 * Returns a new ExceptionSafetyTestBuilder with an included T factory based 973 * on the provided T instance. The existing factory will not be included in 974 * the newly created tester instance. The created factory returns a new T 975 * instance by copy-constructing the provided const T& t. 976 * 977 * Preconditions for tester.WithInitialValue(const T& t): 978 * 979 * - The const T& t object must be copy-constructible where T is the type 980 * being tested. For non-copy-constructible objects, use the method 981 * tester.WithFactory(...). 982 */ 983 template <typename T> 984 ExceptionSafetyTestBuilder<DefaultFactory<T>, Operation, Contracts...> 985 WithInitialValue(const T& t) const { 986 return WithFactory(DefaultFactory<T>(t)); 987 } 988 989 /* 990 * Returns a new ExceptionSafetyTestBuilder with the provided T factory 991 * included. The existing factory will not be included in the newly-created 992 * tester instance. This method is intended for use with types lacking a copy 993 * constructor. Types that can be copy-constructed should instead use the 994 * method tester.WithInitialValue(...). 995 */ 996 template <typename NewFactory> 997 ExceptionSafetyTestBuilder<absl::decay_t<NewFactory>, Operation, Contracts...> 998 WithFactory(const NewFactory& new_factory) const { 999 return {new_factory, operation_, contracts_}; 1000 } 1001 1002 /* 1003 * Returns a new ExceptionSafetyTestBuilder with the provided testable 1004 * operation included. The existing operation will not be included in the 1005 * newly created tester. 1006 */ 1007 template <typename NewOperation> 1008 ExceptionSafetyTestBuilder<Factory, absl::decay_t<NewOperation>, Contracts...> 1009 WithOperation(const NewOperation& new_operation) const { 1010 return {factory_, new_operation, contracts_}; 1011 } 1012 1013 /* 1014 * Returns a new ExceptionSafetyTestBuilder with the provided MoreContracts... 1015 * combined with the Contracts... that were already included in the instance 1016 * on which the method was called. Contracts... cannot be removed or replaced 1017 * once added to an ExceptionSafetyTestBuilder instance. A fresh object must 1018 * be created in order to get an empty Contracts... list. 1019 * 1020 * In addition to passing in custom contract assertion callbacks, this method 1021 * accepts `testing::strong_guarantee` as an argument which checks T instances 1022 * post-throw against freshly created T instances via operator== to verify 1023 * that any state changes made during the execution of the operation were 1024 * properly rolled back. 1025 */ 1026 template <typename... MoreContracts> 1027 ExceptionSafetyTestBuilder<Factory, Operation, Contracts..., 1028 absl::decay_t<MoreContracts>...> 1029 WithContracts(const MoreContracts&... more_contracts) const { 1030 return { 1031 factory_, operation_, 1032 std::tuple_cat(contracts_, std::tuple<absl::decay_t<MoreContracts>...>( 1033 more_contracts...))}; 1034 } 1035 1036 /* 1037 * Returns a testing::AssertionResult that is the reduced result of the 1038 * exception safety algorithm. The algorithm short circuits and returns 1039 * AssertionFailure after the first contract callback returns an 1040 * AssertionFailure. Otherwise, if all contract callbacks return an 1041 * AssertionSuccess, the reduced result is AssertionSuccess. 1042 * 1043 * The passed-in testable operation will not be saved in a new tester instance 1044 * nor will it modify/replace the existing tester instance. This is useful 1045 * when each operation being tested is unique and does not need to be reused. 1046 * 1047 * Preconditions for tester.Test(const NewOperation& new_operation): 1048 * 1049 * - May only be called after at least one contract assertion callback and a 1050 * factory or initial value have been provided. 1051 */ 1052 template < 1053 typename NewOperation, 1054 typename = EnableIfTestable<sizeof...(Contracts), Factory, NewOperation>> 1055 testing::AssertionResult Test(const NewOperation& new_operation) const { 1056 return TestImpl(new_operation, absl::index_sequence_for<Contracts...>()); 1057 } 1058 1059 /* 1060 * Returns a testing::AssertionResult that is the reduced result of the 1061 * exception safety algorithm. The algorithm short circuits and returns 1062 * AssertionFailure after the first contract callback returns an 1063 * AssertionFailure. Otherwise, if all contract callbacks return an 1064 * AssertionSuccess, the reduced result is AssertionSuccess. 1065 * 1066 * Preconditions for tester.Test(): 1067 * 1068 * - May only be called after at least one contract assertion callback, a 1069 * factory or initial value and a testable operation have been provided. 1070 */ 1071 template < 1072 typename LazyOperation = Operation, 1073 typename = EnableIfTestable<sizeof...(Contracts), Factory, LazyOperation>> 1074 testing::AssertionResult Test() const { 1075 return Test(operation_); 1076 } 1077 1078 private: 1079 template <typename, typename, typename...> 1080 friend class ExceptionSafetyTestBuilder; 1081 1082 friend ExceptionSafetyTestBuilder<> testing::MakeExceptionSafetyTester(); 1083 1084 ExceptionSafetyTestBuilder() {} 1085 1086 ExceptionSafetyTestBuilder(const Factory& f, const Operation& o, 1087 const std::tuple<Contracts...>& i) 1088 : factory_(f), operation_(o), contracts_(i) {} 1089 1090 template <typename SelectedOperation, size_t... Indices> 1091 testing::AssertionResult TestImpl(SelectedOperation selected_operation, 1092 absl::index_sequence<Indices...>) const { 1093 return ExceptionSafetyTest<FactoryElementType<Factory>>( 1094 factory_, selected_operation, std::get<Indices>(contracts_)...) 1095 .Test(); 1096 } 1097 1098 Factory factory_; 1099 Operation operation_; 1100 std::tuple<Contracts...> contracts_; 1101 }; 1102 1103 } // namespace exceptions_internal 1104 1105 } // namespace testing 1106 1107 #endif // ABSL_HAVE_EXCEPTIONS 1108 1109 #endif // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_