[llvm] r233310 - [ADT][CMake][AutoConf] Fail-fast iterators for DenseMap

Daniel Sanders Daniel.Sanders at imgtec.com
Mon Mar 30 02:24:52 PDT 2015


Hi,

It seems that this change has broken clang builds where clang is built for an already-compiled llvm. See http://buildbot.llvm.linuxfoundation.org/builders/malta/builds/87/steps/shell_3/logs/stdio for the full log but the relevant part is:
	-- Found LLVM_CONFIG as /home/das/llvm-linux/llvmlinux/toolchain/clang/head/install/bin/llvm-config
	CMake Error at /home/das/llvm-linux/llvmlinux/toolchain/clang/head/install/share/llvm/cmake/HandleLLVMOptions.cmake:92 (message):
	  Unknown value for LLVM_ABI_BREAKING_CHECKS: ""!
	Call Stack (most recent call first):
	  CMakeLists.txt:102 (include)

Should clang be setting this cmake variable from llvm-config or should it be setting it itself?

> -----Original Message-----
> From: llvm-commits-bounces at cs.uiuc.edu [mailto:llvm-commits-
> bounces at cs.uiuc.edu] On Behalf Of Sanjoy Das
> Sent: 26 March 2015 19:25
> To: llvm-commits at cs.uiuc.edu
> Subject: [llvm] r233310 - [ADT][CMake][AutoConf] Fail-fast iterators for
> DenseMap
> 
> Author: sanjoy
> Date: Thu Mar 26 14:25:01 2015
> New Revision: 233310
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=233310&view=rev
> Log:
> [ADT][CMake][AutoConf] Fail-fast iterators for DenseMap
> 
> Summary:
> This patch is an attempt at making `DenseMapIterator`s "fail-fast".
> Fail-fast iterators that have been invalidated due to insertion into
> the host `DenseMap` deterministically trip an assert (in debug mode)
> on access, instead of non-deterministically hitting memory corruption
> issues.
> 
> Enabling fail-fast iterators breaks the LLVM C++ ABI, so they are
> predicated on `LLVM_ENABLE_ABI_BREAKING_CHECKS`.
> `LLVM_ENABLE_ABI_BREAKING_CHECKS` by default flips with
> `LLVM_ENABLE_ASSERTS`, but can be clamped to ON or OFF using the CMake
> /
> autoconf build system.
> 
> Reviewers: chandlerc, dexonsmith, rnk, zturner
> 
> Subscribers: llvm-commits
> 
> Differential Revision: http://reviews.llvm.org/D8351
> 
> Added:
>     llvm/trunk/include/llvm/ADT/EpochTracker.h
> Modified:
>     llvm/trunk/CMakeLists.txt
>     llvm/trunk/autoconf/configure.ac
>     llvm/trunk/cmake/modules/HandleLLVMOptions.cmake
>     llvm/trunk/configure
>     llvm/trunk/docs/CMake.rst
>     llvm/trunk/docs/ProgrammersManual.rst
>     llvm/trunk/include/llvm/ADT/DenseMap.h
>     llvm/trunk/include/llvm/Config/config.h.in
>     llvm/trunk/include/llvm/Config/llvm-config.h.cmake
>     llvm/trunk/include/llvm/Config/llvm-config.h.in
> 
> Modified: llvm/trunk/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-
> project/llvm/trunk/CMakeLists.txt?rev=233310&r1=233309&r2=233310&view
> =diff
> ==========================================================
> ====================
> --- llvm/trunk/CMakeLists.txt (original)
> +++ llvm/trunk/CMakeLists.txt Thu Mar 26 14:25:01 2015
> @@ -252,6 +252,9 @@ else()
>    option(LLVM_ENABLE_ASSERTIONS "Enable assertions" ON)
>  endif()
> 
> +set(LLVM_ABI_BREAKING_CHECKS "WITH_ASSERTS" CACHE STRING
> +  "Enable abi-breaking checks.  Can be WITH_ASSERTS, FORCE_ON or
> FORCE_OFF.")
> +
>  option(LLVM_FORCE_USE_OLD_HOST_TOOLCHAIN
>         "Set to ON to force using an old, unsupported host toolchain." OFF)
> 
> 
> Modified: llvm/trunk/autoconf/configure.ac
> URL: http://llvm.org/viewvc/llvm-
> project/llvm/trunk/autoconf/configure.ac?rev=233310&r1=233309&r2=23331
> 0&view=diff
> ==========================================================
> ====================
> --- llvm/trunk/autoconf/configure.ac (original)
> +++ llvm/trunk/autoconf/configure.ac Thu Mar 26 14:25:01 2015
> @@ -701,8 +701,10 @@ AC_ARG_ENABLE(assertions,AS_HELP_STRING(
>    --enable-assertions,[Compile with assertion checks enabled (default is
> YES)]),, enableval="yes")
>  if test ${enableval} = "yes" ; then
>    AC_SUBST(DISABLE_ASSERTIONS,[[]])
> +  assertions_enabled="yes"
>  else
>    AC_SUBST(DISABLE_ASSERTIONS,[[DISABLE_ASSERTIONS=1]])
> +  assertions_enabled="no"
>  fi
> 
>  dnl --enable-werror : check whether we want Werror on by default
> @@ -726,6 +728,20 @@ else
>    AC_SUBST(EXPENSIVE_CHECKS,[[no]])
>  fi
> 
> +dnl --enable-abi-breaking-checks : decide whether we should compile in
> asserts and
> +dnl checks that make the build ABI incompatible with an llvm built without
> these
> +dnl checks enabled.
> +AC_ARG_ENABLE(abi-breaking-checks,AS_HELP_STRING(
> +  --enable-abi-breaking-checks,[Compile with abi-breaking asserts support
> (default is with-asserts)]),, enableval="with-asserts")
> +case "$enableval" in
> +  with-asserts)  if test ${assertions_enabled} = "yes" ; then
> +                   AC_DEFINE([LLVM_ENABLE_ABI_BREAKING_CHECKS],[1],[Define
> to enable checks that alter the LLVM C++ ABI])
> +		 fi ;;
> +  yes) AC_DEFINE([LLVM_ENABLE_ABI_BREAKING_CHECKS],[1],[Define to
> enable checks that alter the LLVM C++ ABI]) ;;
> +  no) ;;
> +  *) AC_MSG_ERROR([Invalid setting for --enable-abi-breaking-checks.  Use
> "with-asserts", "yes" or "no"])
> +esac
> +
>  dnl --enable-debug-runtime : should runtime libraries have debug symbols?
>  AC_ARG_ENABLE(debug-runtime,
>     AS_HELP_STRING(--enable-debug-runtime,[Build runtime libs with debug
> symbols (default is NO)]),,enableval=no)
> 
> Modified: llvm/trunk/cmake/modules/HandleLLVMOptions.cmake
> URL: http://llvm.org/viewvc/llvm-
> project/llvm/trunk/cmake/modules/HandleLLVMOptions.cmake?rev=23331
> 0&r1=233309&r2=233310&view=diff
> ==========================================================
> ====================
> --- llvm/trunk/cmake/modules/HandleLLVMOptions.cmake (original)
> +++ llvm/trunk/cmake/modules/HandleLLVMOptions.cmake Thu Mar 26
> 14:25:01 2015
> @@ -78,6 +78,20 @@ if( LLVM_ENABLE_ASSERTIONS )
>    endif()
>  endif()
> 
> +string(TOUPPER "${LLVM_ABI_BREAKING_CHECKS}"
> uppercase_LLVM_ABI_BREAKING_CHECKS)
> +
> +if( uppercase_LLVM_ABI_BREAKING_CHECKS STREQUAL "WITH_ASSERTS" )
> +  if( LLVM_ENABLE_ASSERTIONS )
> +    set( LLVM_ENABLE_ABI_BREAKING_CHECKS 1 )
> +  endif()
> +elseif( uppercase_LLVM_ABI_BREAKING_CHECKS STREQUAL "FORCE_ON" )
> +  set( LLVM_ENABLE_ABI_BREAKING_CHECKS 1 )
> +elseif( uppercase_LLVM_ABI_BREAKING_CHECKS STREQUAL "FORCE_OFF"
> )
> +  # We don't need to do anything special to turn off ABI breaking checks.
> +else()
> +  message(FATAL_ERROR "Unknown value for
> LLVM_ABI_BREAKING_CHECKS: \"${LLVM_ABI_BREAKING_CHECKS}\"!")
> +endif()
> +
>  if(WIN32)
>    set(LLVM_HAVE_LINK_VERSION_SCRIPT 0)
>    if(CYGWIN)
> 
> Modified: llvm/trunk/configure
> URL: http://llvm.org/viewvc/llvm-
> project/llvm/trunk/configure?rev=233310&r1=233309&r2=233310&view=diff
> ==========================================================
> ====================
> --- llvm/trunk/configure (original)
> +++ llvm/trunk/configure Thu Mar 26 14:25:01 2015
> @@ -1426,6 +1426,9 @@ Optional Features:
>    --enable-expensive-checks
>                            Compile with expensive debug checks enabled (default
>                            is NO)
> +  --enable-abi-breaking-checks
> +                          Compile with abi-breaking asserts support (default
> +                          is with-asserts)
>    --enable-debug-runtime  Build runtime libs with debug symbols (default is
>                            NO)
>    --enable-debug-symbols  Build compiler with debug symbols (default is NO
> if
> @@ -4980,9 +4983,11 @@ fi
>  if test ${enableval} = "yes" ; then
>    DISABLE_ASSERTIONS=
> 
> +  assertions_enabled="yes"
>  else
>    DISABLE_ASSERTIONS=DISABLE_ASSERTIONS=1
> 
> +  assertions_enabled="no"
>  fi
> 
>  # Check whether --enable-werror was given.
> @@ -5023,6 +5028,32 @@ else
> 
>  fi
> 
> +# Check whether --enable-abi-breaking-checks was given.
> +if test "${enable_abi_breaking_checks+set}" = set; then
> +  enableval=$enable_abi_breaking_checks;
> +else
> +  enableval="with-asserts"
> +fi
> +
> +case "$enableval" in
> +  with-asserts)  if test ${assertions_enabled} = "yes" ; then
> +
> +cat >>confdefs.h <<\_ACEOF
> +#define LLVM_ENABLE_ABI_BREAKING_CHECKS 1
> +_ACEOF
> +
> +		 fi ;;
> +  yes)
> +cat >>confdefs.h <<\_ACEOF
> +#define LLVM_ENABLE_ABI_BREAKING_CHECKS 1
> +_ACEOF
> + ;;
> +  no) ;;
> +  *) { { echo "$as_me:$LINENO: error: Invalid setting for --enable-abi-
> breaking-checks.  Use \"with-asserts\", \"yes\" or \"no\"" >&5
> +echo "$as_me: error: Invalid setting for --enable-abi-breaking-checks.  Use
> \"with-asserts\", \"yes\" or \"no\"" >&2;}
> +   { (exit 1); exit 1; }; }
> +esac
> +
>  # Check whether --enable-debug-runtime was given.
>  if test "${enable_debug_runtime+set}" = set; then
>    enableval=$enable_debug_runtime;
> 
> Modified: llvm/trunk/docs/CMake.rst
> URL: http://llvm.org/viewvc/llvm-
> project/llvm/trunk/docs/CMake.rst?rev=233310&r1=233309&r2=233310&vie
> w=diff
> ==========================================================
> ====================
> --- llvm/trunk/docs/CMake.rst (original)
> +++ llvm/trunk/docs/CMake.rst Thu Mar 26 14:25:01 2015
> @@ -270,6 +270,15 @@ LLVM-specific variables
>  **LLVM_ENABLE_WERROR**:BOOL
>    Stop and fail build, if a compiler warning is triggered. Defaults to OFF.
> 
> +**LLVM_ABI_BREAKING_CHECKS**:STRING
> +  Used to decide if LLVM should be built with ABI breaking checks or
> +  not.  Allowed values are `WITH_ASSERTS` (default), `FORCE_ON` and
> +  `FORCE_OFF`.  `WITH_ASSERTS` turns on ABI breaking checks in an
> +  assertion enabled build.  `FORCE_ON` (`FORCE_OFF`) turns them on
> +  (off) irrespective of whether normal (`NDEBUG` based) assertions are
> +  enabled or not.  A version of LLVM built with ABI breaking checks
> +  is not ABI compatible with a version built without it.
> +
>  **LLVM_BUILD_32_BITS**:BOOL
>    Build 32-bits executables and libraries on 64-bits systems. This option is
>    available only on some 64-bits unix systems. Defaults to OFF.
> 
> Modified: llvm/trunk/docs/ProgrammersManual.rst
> URL: http://llvm.org/viewvc/llvm-
> project/llvm/trunk/docs/ProgrammersManual.rst?rev=233310&r1=233309&r
> 2=233310&view=diff
> ==========================================================
> ====================
> --- llvm/trunk/docs/ProgrammersManual.rst (original)
> +++ llvm/trunk/docs/ProgrammersManual.rst Thu Mar 26 14:25:01 2015
> @@ -2553,6 +2553,22 @@ section on :ref:`isa and dyn_cast <isa>`
>  <HowToSetUpLLVMStyleRTTI>` which describes how you can implement this
>  pattern for use with the LLVM helpers.
> 
> +.. _abi_breaking_checks:
> +
> +ABI Breaking Checks
> +-------------------
> +
> +Checks and asserts that alter the LLVM C++ ABI are predicated on the
> +preprocessor symbol `LLVM_ENABLE_ABI_BREAKING_CHECKS` -- LLVM
> +libraries built with `LLVM_ENABLE_ABI_BREAKING_CHECKS` are not ABI
> +compatible LLVM libraries built without it defined.  By default,
> +turning on assertions also turns on
> `LLVM_ENABLE_ABI_BREAKING_CHECKS`
> +so a default +Asserts build is not ABI compatible with a
> +default -Asserts build.  Clients that want ABI compatibility
> +between +Asserts and -Asserts builds should use the CMake or autoconf
> +build systems to set `LLVM_ENABLE_ABI_BREAKING_CHECKS`
> independently
> +of `LLVM_ENABLE_ASSERTIONS`.
> +
>  .. _coreclasses:
> 
>  The Core LLVM Class Hierarchy Reference
> 
> Modified: llvm/trunk/include/llvm/ADT/DenseMap.h
> URL: http://llvm.org/viewvc/llvm-
> project/llvm/trunk/include/llvm/ADT/DenseMap.h?rev=233310&r1=233309&
> r2=233310&view=diff
> ==========================================================
> ====================
> --- llvm/trunk/include/llvm/ADT/DenseMap.h (original)
> +++ llvm/trunk/include/llvm/ADT/DenseMap.h Thu Mar 26 14:25:01 2015
> @@ -15,6 +15,7 @@
>  #define LLVM_ADT_DENSEMAP_H
> 
>  #include "llvm/ADT/DenseMapInfo.h"
> +#include "llvm/ADT/EpochTracker.h"
>  #include "llvm/Support/AlignOf.h"
>  #include "llvm/Support/Compiler.h"
>  #include "llvm/Support/MathExtras.h"
> @@ -50,7 +51,7 @@ class DenseMapIterator;
> 
>  template <typename DerivedT, typename KeyT, typename ValueT,
> typename KeyInfoT,
>            typename BucketT>
> -class DenseMapBase {
> +class DenseMapBase : public DebugEpochBase {
>  public:
>    typedef unsigned size_type;
>    typedef KeyT key_type;
> @@ -62,16 +63,17 @@ public:
>        const_iterator;
>    inline iterator begin() {
>      // When the map is empty, avoid the overhead of
> AdvancePastEmptyBuckets().
> -    return empty() ? end() : iterator(getBuckets(), getBucketsEnd());
> +    return empty() ? end() : iterator(getBuckets(), getBucketsEnd(), *this);
>    }
>    inline iterator end() {
> -    return iterator(getBucketsEnd(), getBucketsEnd(), true);
> +    return iterator(getBucketsEnd(), getBucketsEnd(), *this, true);
>    }
>    inline const_iterator begin() const {
> -    return empty() ? end() : const_iterator(getBuckets(), getBucketsEnd());
> +    return empty() ? end()
> +                   : const_iterator(getBuckets(), getBucketsEnd(), *this);
>    }
>    inline const_iterator end() const {
> -    return const_iterator(getBucketsEnd(), getBucketsEnd(), true);
> +    return const_iterator(getBucketsEnd(), getBucketsEnd(), *this, true);
>    }
> 
>    bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const {
> @@ -81,11 +83,13 @@ public:
> 
>    /// Grow the densemap so that it has at least Size buckets. Does not shrink
>    void resize(size_type Size) {
> +    incrementEpoch();
>      if (Size > getNumBuckets())
>        grow(Size);
>    }
> 
>    void clear() {
> +    incrementEpoch();
>      if (getNumEntries() == 0 && getNumTombstones() == 0) return;
> 
>      // If the capacity of the array is huge, and the # elements used is small,
> @@ -118,13 +122,13 @@ public:
>    iterator find(const KeyT &Val) {
>      BucketT *TheBucket;
>      if (LookupBucketFor(Val, TheBucket))
> -      return iterator(TheBucket, getBucketsEnd(), true);
> +      return iterator(TheBucket, getBucketsEnd(), *this, true);
>      return end();
>    }
>    const_iterator find(const KeyT &Val) const {
>      const BucketT *TheBucket;
>      if (LookupBucketFor(Val, TheBucket))
> -      return const_iterator(TheBucket, getBucketsEnd(), true);
> +      return const_iterator(TheBucket, getBucketsEnd(), *this, true);
>      return end();
>    }
> 
> @@ -137,14 +141,14 @@ public:
>    iterator find_as(const LookupKeyT &Val) {
>      BucketT *TheBucket;
>      if (LookupBucketFor(Val, TheBucket))
> -      return iterator(TheBucket, getBucketsEnd(), true);
> +      return iterator(TheBucket, getBucketsEnd(), *this, true);
>      return end();
>    }
>    template<class LookupKeyT>
>    const_iterator find_as(const LookupKeyT &Val) const {
>      const BucketT *TheBucket;
>      if (LookupBucketFor(Val, TheBucket))
> -      return const_iterator(TheBucket, getBucketsEnd(), true);
> +      return const_iterator(TheBucket, getBucketsEnd(), *this, true);
>      return end();
>    }
> 
> @@ -163,12 +167,13 @@ public:
>    std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) {
>      BucketT *TheBucket;
>      if (LookupBucketFor(KV.first, TheBucket))
> -      return std::make_pair(iterator(TheBucket, getBucketsEnd(), true),
> +      return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
>                              false); // Already in map.
> 
>      // Otherwise, insert the new element.
>      TheBucket = InsertIntoBucket(KV.first, KV.second, TheBucket);
> -    return std::make_pair(iterator(TheBucket, getBucketsEnd(), true), true);
> +    return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
> +                          true);
>    }
> 
>    // Inserts key,value pair into the map if the key isn't already in the map.
> @@ -177,14 +182,15 @@ public:
>    std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) {
>      BucketT *TheBucket;
>      if (LookupBucketFor(KV.first, TheBucket))
> -      return std::make_pair(iterator(TheBucket, getBucketsEnd(), true),
> +      return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
>                              false); // Already in map.
> -
> +
>      // Otherwise, insert the new element.
>      TheBucket = InsertIntoBucket(std::move(KV.first),
>                                   std::move(KV.second),
>                                   TheBucket);
> -    return std::make_pair(iterator(TheBucket, getBucketsEnd(), true), true);
> +    return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
> +                          true);
>    }
> 
>    /// insert - Range insertion of pairs.
> @@ -431,6 +437,8 @@ private:
>    }
> 
>    BucketT *InsertIntoBucketImpl(const KeyT &Key, BucketT *TheBucket) {
> +    incrementEpoch();
> +
>      // If the load of the hash table is more than 3/4, or if fewer than 1/8 of
>      // the buckets are empty (meaning that many are filled with tombstones),
>      // grow the table.
> @@ -987,9 +995,10 @@ private:
> 
>  template <typename KeyT, typename ValueT, typename KeyInfoT,
> typename Bucket,
>            bool IsConst>
> -class DenseMapIterator {
> +class DenseMapIterator : DebugEpochBase::HandleBase {
>    typedef DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>
> ConstIterator;
>    friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>;
> +  friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, false>;
> 
>  public:
>    typedef ptrdiff_t difference_type;
> @@ -1003,8 +1012,10 @@ private:
>  public:
>    DenseMapIterator() : Ptr(nullptr), End(nullptr) {}
> 
> -  DenseMapIterator(pointer Pos, pointer E, bool NoAdvance = false)
> -    : Ptr(Pos), End(E) {
> +  DenseMapIterator(pointer Pos, pointer E, const DebugEpochBase &Epoch,
> +                   bool NoAdvance = false)
> +      : DebugEpochBase::HandleBase(&Epoch), Ptr(Pos), End(E) {
> +    assert(isHandleInSync() && "invalid construction!");
>      if (!NoAdvance) AdvancePastEmptyBuckets();
>    }
> 
> @@ -1015,28 +1026,40 @@ public:
>              typename = typename std::enable_if<!IsConstSrc && IsConst>::type>
>    DenseMapIterator(
>        const DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, IsConstSrc> &I)
> -      : Ptr(I.Ptr), End(I.End) {}
> +      : DebugEpochBase::HandleBase(I), Ptr(I.Ptr), End(I.End) {}
> 
>    reference operator*() const {
> +    assert(isHandleInSync() && "invalid iterator access!");
>      return *Ptr;
>    }
>    pointer operator->() const {
> +    assert(isHandleInSync() && "invalid iterator access!");
>      return Ptr;
>    }
> 
>    bool operator==(const ConstIterator &RHS) const {
> -    return Ptr == RHS.operator->();
> +    assert((!Ptr || isHandleInSync()) && "handle not in sync!");
> +    assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
> +    assert(getEpochAddress() == RHS.getEpochAddress() &&
> +           "comparing incomparable iterators!");
> +    return Ptr == RHS.Ptr;
>    }
>    bool operator!=(const ConstIterator &RHS) const {
> -    return Ptr != RHS.operator->();
> +    assert((!Ptr || isHandleInSync()) && "handle not in sync!");
> +    assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
> +    assert(getEpochAddress() == RHS.getEpochAddress() &&
> +           "comparing incomparable iterators!");
> +    return Ptr != RHS.Ptr;
>    }
> 
>    inline DenseMapIterator& operator++() {  // Preincrement
> +    assert(isHandleInSync() && "invalid iterator access!");
>      ++Ptr;
>      AdvancePastEmptyBuckets();
>      return *this;
>    }
>    DenseMapIterator operator++(int) {  // Postincrement
> +    assert(isHandleInSync() && "invalid iterator access!");
>      DenseMapIterator tmp = *this; ++*this; return tmp;
>    }
> 
> 
> Added: llvm/trunk/include/llvm/ADT/EpochTracker.h
> URL: http://llvm.org/viewvc/llvm-
> project/llvm/trunk/include/llvm/ADT/EpochTracker.h?rev=233310&view=aut
> o
> ==========================================================
> ====================
> --- llvm/trunk/include/llvm/ADT/EpochTracker.h (added)
> +++ llvm/trunk/include/llvm/ADT/EpochTracker.h Thu Mar 26 14:25:01 2015
> @@ -0,0 +1,99 @@
> +//===- llvm/ADT/EpochTracker.h - ADT epoch tracking --------------*- C++ -*-
> ==//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This file defines the DebugEpochBase and DebugEpochBase::HandleBase
> classes.
> +// These can be used to write iterators that are fail-fast when LLVM is built
> +// with asserts enabled.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_ADT_EPOCH_TRACKER_H
> +#define LLVM_ADT_EPOCH_TRACKER_H
> +
> +#include "llvm/Config/llvm-config.h"
> +
> +#include <cstdint>
> +
> +namespace llvm {
> +
> +#ifndef LLVM_ENABLE_ABI_BREAKING_CHECKS
> +
> +class DebugEpochBase {
> +public:
> +  void incrementEpoch() {}
> +
> +  class HandleBase {
> +  public:
> +    HandleBase() {}
> +    explicit HandleBase(const DebugEpochBase *) {}
> +    bool isHandleInSync() const { return true; }
> +    const void *getEpochAddress() const { return nullptr; }
> +  };
> +};
> +
> +#else
> +
> +/// \brief A base class for data structure classes wishing to make iterators
> +/// ("handles") pointing into themselves fail-fast.  When building without
> +/// asserts, this class is empty and does nothing.
> +///
> +/// DebugEpochBase does not by itself track handles pointing into itself.
> The
> +/// expectation is that routines touching the handles will poll on
> +/// isHandleInSync at appropriate points to assert that the handle they're
> using
> +/// is still valid.
> +///
> +class DebugEpochBase {
> +  uint64_t Epoch;
> +
> +public:
> +  DebugEpochBase() : Epoch(0) {}
> +
> +  /// \brief Calling incrementEpoch invalidates all handles pointing into the
> +  /// calling instance.
> +  void incrementEpoch() { ++Epoch; }
> +
> +  /// \brief The destructor calls incrementEpoch to make use-after-free bugs
> +  /// more likely to crash deterministically.
> +  ~DebugEpochBase() { incrementEpoch(); }
> +
> +  /// \brief A base class for iterator classes ("handles") that wish to poll for
> +  /// iterator invalidating modifications in the underlying data structure.
> +  /// When LLVM is built without asserts, this class is empty and does
> nothing.
> +  ///
> +  /// HandleBase does not track the parent data structure by itself.  It
> expects
> +  /// the routines modifying the data structure to call incrementEpoch when
> they
> +  /// make an iterator-invalidating modification.
> +  ///
> +  class HandleBase {
> +    const uint64_t *EpochAddress;
> +    uint64_t EpochAtCreation;
> +
> +  public:
> +    HandleBase() : EpochAddress(nullptr), EpochAtCreation(UINT64_MAX) {}
> +
> +    explicit HandleBase(const DebugEpochBase *Parent)
> +        : EpochAddress(&Parent->Epoch), EpochAtCreation(Parent->Epoch) {}
> +
> +    /// \brief Returns true if the DebugEpochBase this Handle is linked to has
> +    /// not called incrementEpoch on itself since the creation of this
> +    /// HandleBase instance.
> +    bool isHandleInSync() const { return *EpochAddress == EpochAtCreation;
> }
> +
> +    /// \brief Returns a pointer to the epoch word stored in the data
> structure
> +    /// this handle points into.  Can be used to check if two iterators point
> +    /// into the same data structure.
> +    const void *getEpochAddress() const { return EpochAddress; }
> +  };
> +};
> +
> +#endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
> +
> +} // namespace llvm
> +
> +#endif
> 
> Modified: llvm/trunk/include/llvm/Config/config.h.in
> URL: http://llvm.org/viewvc/llvm-
> project/llvm/trunk/include/llvm/Config/config.h.in?rev=233310&r1=233309&
> r2=233310&view=diff
> ==========================================================
> ====================
> --- llvm/trunk/include/llvm/Config/config.h.in (original)
> +++ llvm/trunk/include/llvm/Config/config.h.in Thu Mar 26 14:25:01 2015
> @@ -417,6 +417,9 @@
>  /* Installation directory for documentation */
>  #undef LLVM_DOCSDIR
> 
> +/* Define to enable checks that alter the LLVM C++ ABI */
> +#undef LLVM_ENABLE_ABI_BREAKING_CHECKS
> +
>  /* Define if threads enabled */
>  #undef LLVM_ENABLE_THREADS
> 
> 
> Modified: llvm/trunk/include/llvm/Config/llvm-config.h.cmake
> URL: http://llvm.org/viewvc/llvm-
> project/llvm/trunk/include/llvm/Config/llvm-
> config.h.cmake?rev=233310&r1=233309&r2=233310&view=diff
> ==========================================================
> ====================
> --- llvm/trunk/include/llvm/Config/llvm-config.h.cmake (original)
> +++ llvm/trunk/include/llvm/Config/llvm-config.h.cmake Thu Mar 26 14:25:01
> 2015
> @@ -101,4 +101,8 @@
>  /* Define if we link Polly to the tools */
>  #cmakedefine LINK_POLLY_INTO_TOOLS
> 
> +/* Define if LLVM is built with asserts and checks that change the layout of
> +   client-visible data structures.  */
> +#cmakedefine LLVM_ENABLE_ABI_BREAKING_CHECKS
> +
>  #endif
> 
> Modified: llvm/trunk/include/llvm/Config/llvm-config.h.in
> URL: http://llvm.org/viewvc/llvm-
> project/llvm/trunk/include/llvm/Config/llvm-
> config.h.in?rev=233310&r1=233309&r2=233310&view=diff
> ==========================================================
> ====================
> --- llvm/trunk/include/llvm/Config/llvm-config.h.in (original)
> +++ llvm/trunk/include/llvm/Config/llvm-config.h.in Thu Mar 26 14:25:01
> 2015
> @@ -98,4 +98,7 @@
>  /* LLVM version string */
>  #undef LLVM_VERSION_STRING
> 
> +/* Define to enable checks that alter the LLVM C++ ABI */
> +#undef LLVM_ENABLE_ABI_BREAKING_CHECKS
> +
>  #endif
> 
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits




More information about the llvm-commits mailing list