Line data Source code
1 : //===- llvm/ADT/EpochTracker.h - ADT epoch tracking --------------*- C++ -*-==//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : //
10 : // This file defines the DebugEpochBase and DebugEpochBase::HandleBase classes.
11 : // These can be used to write iterators that are fail-fast when LLVM is built
12 : // with asserts enabled.
13 : //
14 : //===----------------------------------------------------------------------===//
15 :
16 : #ifndef LLVM_ADT_EPOCH_TRACKER_H
17 : #define LLVM_ADT_EPOCH_TRACKER_H
18 :
19 : #include "llvm/Config/abi-breaking.h"
20 :
21 : #include <cstdint>
22 :
23 : namespace llvm {
24 :
25 : #if LLVM_ENABLE_ABI_BREAKING_CHECKS
26 :
27 : /// A base class for data structure classes wishing to make iterators
28 : /// ("handles") pointing into themselves fail-fast. When building without
29 : /// asserts, this class is empty and does nothing.
30 : ///
31 : /// DebugEpochBase does not by itself track handles pointing into itself. The
32 : /// expectation is that routines touching the handles will poll on
33 : /// isHandleInSync at appropriate points to assert that the handle they're using
34 : /// is still valid.
35 : ///
36 : class DebugEpochBase {
37 : uint64_t Epoch;
38 :
39 : public:
40 : DebugEpochBase() : Epoch(0) {}
41 :
42 : /// Calling incrementEpoch invalidates all handles pointing into the
43 : /// calling instance.
44 : void incrementEpoch() { ++Epoch; }
45 :
46 : /// The destructor calls incrementEpoch to make use-after-free bugs
47 : /// more likely to crash deterministically.
48 : ~DebugEpochBase() { incrementEpoch(); }
49 :
50 : /// A base class for iterator classes ("handles") that wish to poll for
51 : /// iterator invalidating modifications in the underlying data structure.
52 : /// When LLVM is built without asserts, this class is empty and does nothing.
53 : ///
54 : /// HandleBase does not track the parent data structure by itself. It expects
55 : /// the routines modifying the data structure to call incrementEpoch when they
56 : /// make an iterator-invalidating modification.
57 : ///
58 : class HandleBase {
59 : const uint64_t *EpochAddress;
60 : uint64_t EpochAtCreation;
61 :
62 : public:
63 : HandleBase() : EpochAddress(nullptr), EpochAtCreation(UINT64_MAX) {}
64 :
65 : explicit HandleBase(const DebugEpochBase *Parent)
66 : : EpochAddress(&Parent->Epoch), EpochAtCreation(Parent->Epoch) {}
67 :
68 : /// Returns true if the DebugEpochBase this Handle is linked to has
69 : /// not called incrementEpoch on itself since the creation of this
70 : /// HandleBase instance.
71 : bool isHandleInSync() const { return *EpochAddress == EpochAtCreation; }
72 :
73 : /// Returns a pointer to the epoch word stored in the data structure
74 : /// this handle points into. Can be used to check if two iterators point
75 : /// into the same data structure.
76 : const void *getEpochAddress() const { return EpochAddress; }
77 : };
78 : };
79 :
80 : #else
81 :
82 : class DebugEpochBase {
83 : public:
84 0 : void incrementEpoch() {}
85 :
86 : class HandleBase {
87 : public:
88 : HandleBase() = default;
89 : explicit HandleBase(const DebugEpochBase *) {}
90 : bool isHandleInSync() const { return true; }
91 : const void *getEpochAddress() const { return nullptr; }
92 : };
93 : };
94 :
95 : #endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
96 :
97 : } // namespace llvm
98 :
99 : #endif
|