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