• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
TestException(absl::string_view msg)78   explicit TestException(absl::string_view msg) : msg_(msg) {}
~TestException()79   virtual ~TestException() {}
what()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:
TestBadAllocException(absl::string_view msg)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
UnsetCountdown()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:
ConstructorTracker(int count)120   explicit ConstructorTracker(int count) : countdown_(count) {
121     assert(current_tracker_instance_ == nullptr);
122     current_tracker_instance_ = this;
123   }
124 
~ConstructorTracker()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 
ObjectConstructed(void * address,std::string description)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 
ObjectDestructed(void * address)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:
CurrentlyTracking()171   static bool CurrentlyTracking() {
172     return current_tracker_instance_ != nullptr;
173   }
174 
ErrorMessage(void * address,const std::string & address_description,int countdown,const std::string & error_description)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:
TrackedObject(std::string description)199   explicit TrackedObject(std::string description) {
200     ConstructorTracker::ObjectConstructed(this, std::move(description));
201   }
202 
~TrackedObject()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:
ThrowingBool(bool b)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 {
IsSpecified(TypeSpec spec)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:
ThrowingValue()266   ThrowingValue() : TrackedObject(GetInstanceString(kDefaultValue)) {
267     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
268     dummy_ = kDefaultValue;
269   }
270 
noexcept(IsSpecified (TypeSpec::kNoThrowCopy))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 
noexcept(IsSpecified (TypeSpec::kNoThrowMove))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 
ThrowingValue(int i)289   explicit ThrowingValue(int i) : TrackedObject(GetInstanceString(i)) {
290     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
291     dummy_ = i;
292   }
293 
ThrowingValue(int i,exceptions_internal::NoThrowTag)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 
noexcept(IsSpecified (TypeSpec::kNoThrowCopy))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 
noexcept(IsSpecified (TypeSpec::kNoThrowMove))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
new(size_t s)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 
noexcept(IsSpecified (TypeSpec::kNoThrowNew))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>
new(size_t s,Args &&...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>
noexcept(IsSpecified (TypeSpec::kNoThrowNew))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.
delete(void * p)575   void operator delete(void* p) noexcept { ::operator delete(p); }
576 
577   template <typename... Args>
delete(void * p,Args &&...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.
Get()591   int& Get() noexcept { return dummy_; }
Get()592   const int& Get() const noexcept { return dummy_; }
593 
594  private:
GetInstanceString(int dummy)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 {
IsSpecified(AllocSpec spec)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 
ThrowingAllocator()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>
ThrowingAllocator(const ThrowingAllocator<U,Spec> & other)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.
ThrowingAllocator(const ThrowingAllocator & other)665   ThrowingAllocator(const ThrowingAllocator& other) noexcept
666       : TrackedObject(GetInstanceString(*other.State())),
667         dummy_(other.State()) {}
668 
669   template <typename U>
ThrowingAllocator(ThrowingAllocator<U,Spec> && other)670   ThrowingAllocator(ThrowingAllocator<U, Spec>&& other) noexcept  // NOLINT
671       : TrackedObject(GetInstanceString(*other.State())),
672         dummy_(std::move(other.State())) {}
673 
ThrowingAllocator(ThrowingAllocator && other)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 
allocate(size_type n)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 
allocate(size_type n,const_void_pointer)709   pointer allocate(size_type n, const_void_pointer) noexcept(
710       IsSpecified(AllocSpec::kNoThrowAllocate)) {
711     return allocate(n);
712   }
713 
deallocate(pointer ptr,size_type)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>
construct(U * ptr,Args &&...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>
destroy(U * p)727   void destroy(U* p) noexcept {
728     ReadState();
729     p->~U();
730   }
731 
max_size()732   size_type max_size() const noexcept {
733     return (std::numeric_limits<difference_type>::max)() / sizeof(value_type);
734   }
735 
select_on_container_copy_construction()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:
GetInstanceString(int dummy)756   static std::string GetInstanceString(int dummy) {
757     return absl::StrCat("ThrowingAllocator<",
758                         exceptions_internal::GetSpecString(Spec), ">(", dummy,
759                         ")");
760   }
761 
State()762   const std::shared_ptr<const int>& State() const { return dummy_; }
State()763   std::shared_ptr<const int>& State() { return dummy_; }
764 
ReadState()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 
ReadStateAndMaybeThrow(absl::string_view msg)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>
TestThrowingCtor(Args &&...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>
TestNothrowOp(const Operation & 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:
DefaultFactory(const T & t)836   explicit DefaultFactory(const T& t) : t_(t) {}
operator()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_
1110