| 1 | //===- llvm/ADT/EpochTracker.h - ADT epoch tracking --------------*- C++ -*-==// | 
| 2 | // | 
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
| 4 | // See https://llvm.org/LICENSE.txt for license information. | 
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
| 6 | // | 
| 7 | //===----------------------------------------------------------------------===// | 
| 8 | /// | 
| 9 | /// \file | 
| 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_EPOCHTRACKER_H | 
| 17 | #define LLVM_ADT_EPOCHTRACKER_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 | #define LLVM_DEBUGEPOCHBASE_HANDLEBASE_EMPTYBASE | 
| 27 |  | 
| 28 | /// A base class for data structure classes wishing to make iterators | 
| 29 | /// ("handles") pointing into themselves fail-fast.  When building without | 
| 30 | /// asserts, this class is empty and does nothing. | 
| 31 | /// | 
| 32 | /// DebugEpochBase does not by itself track handles pointing into itself.  The | 
| 33 | /// expectation is that routines touching the handles will poll on | 
| 34 | /// isHandleInSync at appropriate points to assert that the handle they're using | 
| 35 | /// is still valid. | 
| 36 | /// | 
| 37 | class DebugEpochBase { | 
| 38 |   uint64_t Epoch = 0; | 
| 39 |  | 
| 40 | public: | 
| 41 |   DebugEpochBase() = default; | 
| 42 |  | 
| 43 |   /// Calling incrementEpoch invalidates all handles pointing into the | 
| 44 |   /// calling instance. | 
| 45 |   void incrementEpoch() { ++Epoch; } | 
| 46 |  | 
| 47 |   /// The destructor calls incrementEpoch to make use-after-free bugs | 
| 48 |   /// more likely to crash deterministically. | 
| 49 |   ~DebugEpochBase() { incrementEpoch(); } | 
| 50 |  | 
| 51 |   /// A base class for iterator classes ("handles") that wish to poll for | 
| 52 |   /// iterator invalidating modifications in the underlying data structure. | 
| 53 |   /// When LLVM is built without asserts, this class is empty and does nothing. | 
| 54 |   /// | 
| 55 |   /// HandleBase does not track the parent data structure by itself.  It expects | 
| 56 |   /// the routines modifying the data structure to call incrementEpoch when they | 
| 57 |   /// make an iterator-invalidating modification. | 
| 58 |   /// | 
| 59 |   class HandleBase { | 
| 60 |     const uint64_t *EpochAddress = nullptr; | 
| 61 |     uint64_t EpochAtCreation = UINT64_MAX; | 
| 62 |  | 
| 63 |   public: | 
| 64 |     HandleBase() = default; | 
| 65 |  | 
| 66 |     explicit HandleBase(const DebugEpochBase *Parent) | 
| 67 |         : EpochAddress(&Parent->Epoch), EpochAtCreation(Parent->Epoch) {} | 
| 68 |  | 
| 69 |     /// Returns true if the DebugEpochBase this Handle is linked to has | 
| 70 |     /// not called incrementEpoch on itself since the creation of this | 
| 71 |     /// HandleBase instance. | 
| 72 |     bool isHandleInSync() const { return *EpochAddress == EpochAtCreation; } | 
| 73 |  | 
| 74 |     /// Returns a pointer to the epoch word stored in the data structure | 
| 75 |     /// this handle points into.  Can be used to check if two iterators point | 
| 76 |     /// into the same data structure. | 
| 77 |     const void *getEpochAddress() const { return EpochAddress; } | 
| 78 |   }; | 
| 79 | }; | 
| 80 |  | 
| 81 | #else | 
| 82 | #ifdef _MSC_VER | 
| 83 | #define LLVM_DEBUGEPOCHBASE_HANDLEBASE_EMPTYBASE __declspec(empty_bases) | 
| 84 | #else | 
| 85 | #define LLVM_DEBUGEPOCHBASE_HANDLEBASE_EMPTYBASE | 
| 86 | #endif // _MSC_VER | 
| 87 |  | 
| 88 | class DebugEpochBase { | 
| 89 | public: | 
| 90 |   void incrementEpoch() {} | 
| 91 |  | 
| 92 |   class HandleBase { | 
| 93 |   public: | 
| 94 |     HandleBase() = default; | 
| 95 |     explicit HandleBase(const DebugEpochBase *) {} | 
| 96 |     bool isHandleInSync() const { return true; } | 
| 97 |     const void *getEpochAddress() const { return nullptr; } | 
| 98 |   }; | 
| 99 | }; | 
| 100 |  | 
| 101 | #endif // LLVM_ENABLE_ABI_BREAKING_CHECKS | 
| 102 |  | 
| 103 | } // namespace llvm | 
| 104 |  | 
| 105 | #endif | 
| 106 |  |