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
539 // Args.. allows us to overload regular and placement new in one shot
540 template <typename... Args>
new(size_t s,Args &&...args)541 static void* operator new(size_t s, Args&&... args) noexcept(
542 IsSpecified(TypeSpec::kNoThrowNew)) {
543 if (!IsSpecified(TypeSpec::kNoThrowNew)) {
544 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
545 }
546 return ::operator new(s, std::forward<Args>(args)...);
547 }
548
549 template <typename... Args>
noexcept(IsSpecified (TypeSpec::kNoThrowNew))550 static void* operator new[](size_t s, Args&&... args) noexcept(
551 IsSpecified(TypeSpec::kNoThrowNew)) {
552 if (!IsSpecified(TypeSpec::kNoThrowNew)) {
553 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
554 }
555 return ::operator new[](s, std::forward<Args>(args)...);
556 }
557
558 // Abseil doesn't support throwing overloaded operator delete. These are
559 // provided so a throwing operator-new can clean up after itself.
560 //
561 // We provide both regular and templated operator delete because if only the
562 // templated version is provided as we did with operator new, the compiler has
563 // no way of knowing which overload of operator delete to call. See
564 // https://en.cppreference.com/w/cpp/memory/new/operator_delete and
565 // https://en.cppreference.com/w/cpp/language/delete for the gory details.
delete(void * p)566 void operator delete(void* p) noexcept { ::operator delete(p); }
567
568 template <typename... Args>
delete(void * p,Args &&...args)569 void operator delete(void* p, Args&&... args) noexcept {
570 ::operator delete(p, std::forward<Args>(args)...);
571 }
572
573 void operator delete[](void* p) noexcept { return ::operator delete[](p); }
574
575 template <typename... Args>
576 void operator delete[](void* p, Args&&... args) noexcept {
577 return ::operator delete[](p, std::forward<Args>(args)...);
578 }
579
580 // Non-standard access to the actual contained value. No need for this to
581 // throw.
Get()582 int& Get() noexcept { return dummy_; }
Get()583 const int& Get() const noexcept { return dummy_; }
584
585 private:
GetInstanceString(int dummy)586 static std::string GetInstanceString(int dummy) {
587 return absl::StrCat("ThrowingValue<",
588 exceptions_internal::GetSpecString(Spec), ">(", dummy,
589 ")");
590 }
591
592 int dummy_;
593 };
594 // While not having to do with exceptions, explicitly delete comma operator, to
595 // make sure we don't use it on user-supplied types.
596 template <TypeSpec Spec, typename T>
597 void operator,(const ThrowingValue<Spec>&, T&&) = delete;
598 template <TypeSpec Spec, typename T>
599 void operator,(T&&, const ThrowingValue<Spec>&) = delete;
600
601 /*
602 * Configuration enum for the ThrowingAllocator type that defines behavior for
603 * the lifetime of the instance.
604 *
605 * kEverythingThrows: Calls to the member functions may throw
606 * kNoThrowAllocate: Calls to the member functions will not throw
607 */
608 enum class AllocSpec {
609 kEverythingThrows = 0,
610 kNoThrowAllocate = 1,
611 };
612
613 /*
614 * An allocator type which is instrumented to throw at a controlled time, or not
615 * to throw, using AllocSpec. The supported settings are the default of every
616 * function which is allowed to throw in a conforming allocator possibly
617 * throwing, or nothing throws, in line with the ABSL_ALLOCATOR_THROWS
618 * configuration macro.
619 */
620 template <typename T, AllocSpec Spec = AllocSpec::kEverythingThrows>
621 class ThrowingAllocator : private exceptions_internal::TrackedObject {
IsSpecified(AllocSpec spec)622 static constexpr bool IsSpecified(AllocSpec spec) {
623 return static_cast<bool>(Spec & spec);
624 }
625
626 public:
627 using pointer = T*;
628 using const_pointer = const T*;
629 using reference = T&;
630 using const_reference = const T&;
631 using void_pointer = void*;
632 using const_void_pointer = const void*;
633 using value_type = T;
634 using size_type = size_t;
635 using difference_type = ptrdiff_t;
636
637 using is_nothrow =
638 std::integral_constant<bool, Spec == AllocSpec::kNoThrowAllocate>;
639 using propagate_on_container_copy_assignment = std::true_type;
640 using propagate_on_container_move_assignment = std::true_type;
641 using propagate_on_container_swap = std::true_type;
642 using is_always_equal = std::false_type;
643
ThrowingAllocator()644 ThrowingAllocator() : TrackedObject(GetInstanceString(next_id_)) {
645 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
646 dummy_ = std::make_shared<const int>(next_id_++);
647 }
648
649 template <typename U>
ThrowingAllocator(const ThrowingAllocator<U,Spec> & other)650 ThrowingAllocator(const ThrowingAllocator<U, Spec>& other) noexcept // NOLINT
651 : TrackedObject(GetInstanceString(*other.State())),
652 dummy_(other.State()) {}
653
654 // According to C++11 standard [17.6.3.5], Table 28, the move/copy ctors of
655 // allocator shall not exit via an exception, thus they are marked noexcept.
ThrowingAllocator(const ThrowingAllocator & other)656 ThrowingAllocator(const ThrowingAllocator& other) noexcept
657 : TrackedObject(GetInstanceString(*other.State())),
658 dummy_(other.State()) {}
659
660 template <typename U>
ThrowingAllocator(ThrowingAllocator<U,Spec> && other)661 ThrowingAllocator(ThrowingAllocator<U, Spec>&& other) noexcept // NOLINT
662 : TrackedObject(GetInstanceString(*other.State())),
663 dummy_(std::move(other.State())) {}
664
ThrowingAllocator(ThrowingAllocator && other)665 ThrowingAllocator(ThrowingAllocator&& other) noexcept
666 : TrackedObject(GetInstanceString(*other.State())),
667 dummy_(std::move(other.State())) {}
668
669 ~ThrowingAllocator() noexcept = default;
670
671 ThrowingAllocator& operator=(const ThrowingAllocator& other) noexcept {
672 dummy_ = other.State();
673 return *this;
674 }
675
676 template <typename U>
677 ThrowingAllocator& operator=(
678 const ThrowingAllocator<U, Spec>& other) noexcept {
679 dummy_ = other.State();
680 return *this;
681 }
682
683 template <typename U>
684 ThrowingAllocator& operator=(ThrowingAllocator<U, Spec>&& other) noexcept {
685 dummy_ = std::move(other.State());
686 return *this;
687 }
688
689 template <typename U>
690 struct rebind {
691 using other = ThrowingAllocator<U, Spec>;
692 };
693
allocate(size_type n)694 pointer allocate(size_type n) noexcept(
695 IsSpecified(AllocSpec::kNoThrowAllocate)) {
696 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
697 return static_cast<pointer>(::operator new(n * sizeof(T)));
698 }
699
allocate(size_type n,const_void_pointer)700 pointer allocate(size_type n, const_void_pointer) noexcept(
701 IsSpecified(AllocSpec::kNoThrowAllocate)) {
702 return allocate(n);
703 }
704
deallocate(pointer ptr,size_type)705 void deallocate(pointer ptr, size_type) noexcept {
706 ReadState();
707 ::operator delete(static_cast<void*>(ptr));
708 }
709
710 template <typename U, typename... Args>
construct(U * ptr,Args &&...args)711 void construct(U* ptr, Args&&... args) noexcept(
712 IsSpecified(AllocSpec::kNoThrowAllocate)) {
713 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
714 ::new (static_cast<void*>(ptr)) U(std::forward<Args>(args)...);
715 }
716
717 template <typename U>
destroy(U * p)718 void destroy(U* p) noexcept {
719 ReadState();
720 p->~U();
721 }
722
max_size()723 size_type max_size() const noexcept {
724 return (std::numeric_limits<difference_type>::max)() / sizeof(value_type);
725 }
726
select_on_container_copy_construction()727 ThrowingAllocator select_on_container_copy_construction() noexcept(
728 IsSpecified(AllocSpec::kNoThrowAllocate)) {
729 auto& out = *this;
730 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
731 return out;
732 }
733
734 template <typename U>
735 bool operator==(const ThrowingAllocator<U, Spec>& other) const noexcept {
736 return dummy_ == other.dummy_;
737 }
738
739 template <typename U>
740 bool operator!=(const ThrowingAllocator<U, Spec>& other) const noexcept {
741 return dummy_ != other.dummy_;
742 }
743
744 template <typename, AllocSpec>
745 friend class ThrowingAllocator;
746
747 private:
GetInstanceString(int dummy)748 static std::string GetInstanceString(int dummy) {
749 return absl::StrCat("ThrowingAllocator<",
750 exceptions_internal::GetSpecString(Spec), ">(", dummy,
751 ")");
752 }
753
State()754 const std::shared_ptr<const int>& State() const { return dummy_; }
State()755 std::shared_ptr<const int>& State() { return dummy_; }
756
ReadState()757 void ReadState() {
758 // we know that this will never be true, but the compiler doesn't, so this
759 // should safely force a read of the value.
760 if (*dummy_ < 0) std::abort();
761 }
762
ReadStateAndMaybeThrow(absl::string_view msg)763 void ReadStateAndMaybeThrow(absl::string_view msg) const {
764 if (!IsSpecified(AllocSpec::kNoThrowAllocate)) {
765 exceptions_internal::MaybeThrow(
766 absl::Substitute("Allocator id $0 threw from $1", *dummy_, msg));
767 }
768 }
769
770 static int next_id_;
771 std::shared_ptr<const int> dummy_;
772 };
773
774 template <typename T, AllocSpec Spec>
775 int ThrowingAllocator<T, Spec>::next_id_ = 0;
776
777 // Tests for resource leaks by attempting to construct a T using args repeatedly
778 // until successful, using the countdown method. Side effects can then be
779 // tested for resource leaks.
780 template <typename T, typename... Args>
TestThrowingCtor(Args &&...args)781 void TestThrowingCtor(Args&&... args) {
782 struct Cleanup {
783 ~Cleanup() { exceptions_internal::UnsetCountdown(); }
784 } c;
785 for (int count = 0;; ++count) {
786 exceptions_internal::ConstructorTracker ct(count);
787 exceptions_internal::SetCountdown(count);
788 try {
789 T temp(std::forward<Args>(args)...);
790 static_cast<void>(temp);
791 break;
792 } catch (const exceptions_internal::TestException&) {
793 }
794 }
795 }
796
797 // Tests the nothrow guarantee of the provided nullary operation. If the an
798 // exception is thrown, the result will be AssertionFailure(). Otherwise, it
799 // will be AssertionSuccess().
800 template <typename Operation>
TestNothrowOp(const Operation & operation)801 testing::AssertionResult TestNothrowOp(const Operation& operation) {
802 struct Cleanup {
803 Cleanup() { exceptions_internal::SetCountdown(); }
804 ~Cleanup() { exceptions_internal::UnsetCountdown(); }
805 } c;
806 try {
807 operation();
808 return testing::AssertionSuccess();
809 } catch (const exceptions_internal::TestException&) {
810 return testing::AssertionFailure()
811 << "TestException thrown during call to operation() when nothrow "
812 "guarantee was expected.";
813 } catch (...) {
814 return testing::AssertionFailure()
815 << "Unknown exception thrown during call to operation() when "
816 "nothrow guarantee was expected.";
817 }
818 }
819
820 namespace exceptions_internal {
821
822 // Dummy struct for ExceptionSafetyTestBuilder<> partial state.
823 struct UninitializedT {};
824
825 template <typename T>
826 class DefaultFactory {
827 public:
DefaultFactory(const T & t)828 explicit DefaultFactory(const T& t) : t_(t) {}
operator()829 std::unique_ptr<T> operator()() const { return absl::make_unique<T>(t_); }
830
831 private:
832 T t_;
833 };
834
835 template <size_t LazyContractsCount, typename LazyFactory,
836 typename LazyOperation>
837 using EnableIfTestable = typename absl::enable_if_t<
838 LazyContractsCount != 0 &&
839 !std::is_same<LazyFactory, UninitializedT>::value &&
840 !std::is_same<LazyOperation, UninitializedT>::value>;
841
842 template <typename Factory = UninitializedT,
843 typename Operation = UninitializedT, typename... Contracts>
844 class ExceptionSafetyTestBuilder;
845
846 } // namespace exceptions_internal
847
848 /*
849 * Constructs an empty ExceptionSafetyTestBuilder. All
850 * ExceptionSafetyTestBuilder objects are immutable and all With[thing] mutation
851 * methods return new instances of ExceptionSafetyTestBuilder.
852 *
853 * In order to test a T for exception safety, a factory for that T, a testable
854 * operation, and at least one contract callback returning an assertion
855 * result must be applied using the respective methods.
856 */
857 exceptions_internal::ExceptionSafetyTestBuilder<> MakeExceptionSafetyTester();
858
859 namespace exceptions_internal {
860 template <typename T>
861 struct IsUniquePtr : std::false_type {};
862
863 template <typename T, typename D>
864 struct IsUniquePtr<std::unique_ptr<T, D>> : std::true_type {};
865
866 template <typename Factory>
867 struct FactoryPtrTypeHelper {
868 using type = decltype(std::declval<const Factory&>()());
869
870 static_assert(IsUniquePtr<type>::value, "Factories must return a unique_ptr");
871 };
872
873 template <typename Factory>
874 using FactoryPtrType = typename FactoryPtrTypeHelper<Factory>::type;
875
876 template <typename Factory>
877 using FactoryElementType = typename FactoryPtrType<Factory>::element_type;
878
879 template <typename T>
880 class ExceptionSafetyTest {
881 using Factory = std::function<std::unique_ptr<T>()>;
882 using Operation = std::function<void(T*)>;
883 using Contract = std::function<AssertionResult(T*)>;
884
885 public:
886 template <typename... Contracts>
887 explicit ExceptionSafetyTest(const Factory& f, const Operation& op,
888 const Contracts&... contracts)
889 : factory_(f), operation_(op), contracts_{WrapContract(contracts)...} {}
890
891 AssertionResult Test() const {
892 for (int count = 0;; ++count) {
893 exceptions_internal::ConstructorTracker ct(count);
894
895 for (const auto& contract : contracts_) {
896 auto t_ptr = factory_();
897 try {
898 SetCountdown(count);
899 operation_(t_ptr.get());
900 // Unset for the case that the operation throws no exceptions, which
901 // would leave the countdown set and break the *next* exception safety
902 // test after this one.
903 UnsetCountdown();
904 return AssertionSuccess();
905 } catch (const exceptions_internal::TestException& e) {
906 if (!contract(t_ptr.get())) {
907 return AssertionFailure() << e.what() << " failed contract check";
908 }
909 }
910 }
911 }
912 }
913
914 private:
915 template <typename ContractFn>
916 Contract WrapContract(const ContractFn& contract) {
917 return [contract](T* t_ptr) { return AssertionResult(contract(t_ptr)); };
918 }
919
920 Contract WrapContract(StrongGuaranteeTagType) {
921 return [this](T* t_ptr) { return AssertionResult(*factory_() == *t_ptr); };
922 }
923
924 Factory factory_;
925 Operation operation_;
926 std::vector<Contract> contracts_;
927 };
928
929 /*
930 * Builds a tester object that tests if performing a operation on a T follows
931 * exception safety guarantees. Verification is done via contract assertion
932 * callbacks applied to T instances post-throw.
933 *
934 * Template parameters for ExceptionSafetyTestBuilder:
935 *
936 * - Factory: The factory object (passed in via tester.WithFactory(...) or
937 * tester.WithInitialValue(...)) must be invocable with the signature
938 * `std::unique_ptr<T> operator()() const` where T is the type being tested.
939 * It is used for reliably creating identical T instances to test on.
940 *
941 * - Operation: The operation object (passsed in via tester.WithOperation(...)
942 * or tester.Test(...)) must be invocable with the signature
943 * `void operator()(T*) const` where T is the type being tested. It is used
944 * for performing steps on a T instance that may throw and that need to be
945 * checked for exception safety. Each call to the operation will receive a
946 * fresh T instance so it's free to modify and destroy the T instances as it
947 * pleases.
948 *
949 * - Contracts...: The contract assertion callback objects (passed in via
950 * tester.WithContracts(...)) must be invocable with the signature
951 * `testing::AssertionResult operator()(T*) const` where T is the type being
952 * tested. Contract assertion callbacks are provided T instances post-throw.
953 * They must return testing::AssertionSuccess when the type contracts of the
954 * provided T instance hold. If the type contracts of the T instance do not
955 * hold, they must return testing::AssertionFailure. Execution order of
956 * Contracts... is unspecified. They will each individually get a fresh T
957 * instance so they are free to modify and destroy the T instances as they
958 * please.
959 */
960 template <typename Factory, typename Operation, typename... Contracts>
961 class ExceptionSafetyTestBuilder {
962 public:
963 /*
964 * Returns a new ExceptionSafetyTestBuilder with an included T factory based
965 * on the provided T instance. The existing factory will not be included in
966 * the newly created tester instance. The created factory returns a new T
967 * instance by copy-constructing the provided const T& t.
968 *
969 * Preconditions for tester.WithInitialValue(const T& t):
970 *
971 * - The const T& t object must be copy-constructible where T is the type
972 * being tested. For non-copy-constructible objects, use the method
973 * tester.WithFactory(...).
974 */
975 template <typename T>
976 ExceptionSafetyTestBuilder<DefaultFactory<T>, Operation, Contracts...>
977 WithInitialValue(const T& t) const {
978 return WithFactory(DefaultFactory<T>(t));
979 }
980
981 /*
982 * Returns a new ExceptionSafetyTestBuilder with the provided T factory
983 * included. The existing factory will not be included in the newly-created
984 * tester instance. This method is intended for use with types lacking a copy
985 * constructor. Types that can be copy-constructed should instead use the
986 * method tester.WithInitialValue(...).
987 */
988 template <typename NewFactory>
989 ExceptionSafetyTestBuilder<absl::decay_t<NewFactory>, Operation, Contracts...>
990 WithFactory(const NewFactory& new_factory) const {
991 return {new_factory, operation_, contracts_};
992 }
993
994 /*
995 * Returns a new ExceptionSafetyTestBuilder with the provided testable
996 * operation included. The existing operation will not be included in the
997 * newly created tester.
998 */
999 template <typename NewOperation>
1000 ExceptionSafetyTestBuilder<Factory, absl::decay_t<NewOperation>, Contracts...>
1001 WithOperation(const NewOperation& new_operation) const {
1002 return {factory_, new_operation, contracts_};
1003 }
1004
1005 /*
1006 * Returns a new ExceptionSafetyTestBuilder with the provided MoreContracts...
1007 * combined with the Contracts... that were already included in the instance
1008 * on which the method was called. Contracts... cannot be removed or replaced
1009 * once added to an ExceptionSafetyTestBuilder instance. A fresh object must
1010 * be created in order to get an empty Contracts... list.
1011 *
1012 * In addition to passing in custom contract assertion callbacks, this method
1013 * accepts `testing::strong_guarantee` as an argument which checks T instances
1014 * post-throw against freshly created T instances via operator== to verify
1015 * that any state changes made during the execution of the operation were
1016 * properly rolled back.
1017 */
1018 template <typename... MoreContracts>
1019 ExceptionSafetyTestBuilder<Factory, Operation, Contracts...,
1020 absl::decay_t<MoreContracts>...>
1021 WithContracts(const MoreContracts&... more_contracts) const {
1022 return {
1023 factory_, operation_,
1024 std::tuple_cat(contracts_, std::tuple<absl::decay_t<MoreContracts>...>(
1025 more_contracts...))};
1026 }
1027
1028 /*
1029 * Returns a testing::AssertionResult that is the reduced result of the
1030 * exception safety algorithm. The algorithm short circuits and returns
1031 * AssertionFailure after the first contract callback returns an
1032 * AssertionFailure. Otherwise, if all contract callbacks return an
1033 * AssertionSuccess, the reduced result is AssertionSuccess.
1034 *
1035 * The passed-in testable operation will not be saved in a new tester instance
1036 * nor will it modify/replace the existing tester instance. This is useful
1037 * when each operation being tested is unique and does not need to be reused.
1038 *
1039 * Preconditions for tester.Test(const NewOperation& new_operation):
1040 *
1041 * - May only be called after at least one contract assertion callback and a
1042 * factory or initial value have been provided.
1043 */
1044 template <
1045 typename NewOperation,
1046 typename = EnableIfTestable<sizeof...(Contracts), Factory, NewOperation>>
1047 testing::AssertionResult Test(const NewOperation& new_operation) const {
1048 return TestImpl(new_operation, absl::index_sequence_for<Contracts...>());
1049 }
1050
1051 /*
1052 * Returns a testing::AssertionResult that is the reduced result of the
1053 * exception safety algorithm. The algorithm short circuits and returns
1054 * AssertionFailure after the first contract callback returns an
1055 * AssertionFailure. Otherwise, if all contract callbacks return an
1056 * AssertionSuccess, the reduced result is AssertionSuccess.
1057 *
1058 * Preconditions for tester.Test():
1059 *
1060 * - May only be called after at least one contract assertion callback, a
1061 * factory or initial value and a testable operation have been provided.
1062 */
1063 template <
1064 typename LazyOperation = Operation,
1065 typename = EnableIfTestable<sizeof...(Contracts), Factory, LazyOperation>>
1066 testing::AssertionResult Test() const {
1067 return Test(operation_);
1068 }
1069
1070 private:
1071 template <typename, typename, typename...>
1072 friend class ExceptionSafetyTestBuilder;
1073
1074 friend ExceptionSafetyTestBuilder<> testing::MakeExceptionSafetyTester();
1075
1076 ExceptionSafetyTestBuilder() {}
1077
1078 ExceptionSafetyTestBuilder(const Factory& f, const Operation& o,
1079 const std::tuple<Contracts...>& i)
1080 : factory_(f), operation_(o), contracts_(i) {}
1081
1082 template <typename SelectedOperation, size_t... Indices>
1083 testing::AssertionResult TestImpl(SelectedOperation selected_operation,
1084 absl::index_sequence<Indices...>) const {
1085 return ExceptionSafetyTest<FactoryElementType<Factory>>(
1086 factory_, selected_operation, std::get<Indices>(contracts_)...)
1087 .Test();
1088 }
1089
1090 Factory factory_;
1091 Operation operation_;
1092 std::tuple<Contracts...> contracts_;
1093 };
1094
1095 } // namespace exceptions_internal
1096
1097 } // namespace testing
1098
1099 #endif // ABSL_HAVE_EXCEPTIONS
1100
1101 #endif // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
1102