[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