tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

NonDereferenceable.h (4630B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_NonDereferenceable_h
      8 #define mozilla_NonDereferenceable_h
      9 
     10 /* A pointer wrapper indicating that the pointer should not be dereferenced. */
     11 
     12 #include "mozilla/Attributes.h"
     13 
     14 #include <cstdint>
     15 
     16 // Macro indicating that a function manipulates a pointer that will not be
     17 // dereferenced, and therefore there is no need to check the object.
     18 #if defined(__clang__)
     19 #  define NO_POINTEE_CHECKS __attribute__((no_sanitize("vptr")))
     20 #else
     21 #  define NO_POINTEE_CHECKS /* nothing */
     22 #endif
     23 
     24 namespace mozilla {
     25 
     26 // NonDereferenceable<T> wraps a raw pointer value of type T*, but prevents
     27 // dereferencing.
     28 //
     29 // The main use case is for pointers that referencing memory that may not
     30 // contain a valid object, either because the object has already been freed, or
     31 // is under active construction or destruction (and hence parts of it may be
     32 // uninitialized or destructed.)
     33 // Such a pointer may still be useful, e.g., for its numeric value for
     34 // logging/debugging purposes, which may be accessed with `value()`.
     35 // Using NonDereferenceable with such pointers will make this intent clearer,
     36 // and prevent misuses.
     37 //
     38 // Note that NonDereferenceable is only a wrapper and is NOT an owning pointer,
     39 // i.e., it will not release/free the object.
     40 //
     41 // NonDereferenceable allows conversions between compatible pointer types, e.g.,
     42 // to navigate a class hierarchy and identify parent/sub-objects. Note that the
     43 // converted pointers stay safely NonDereferenceable.
     44 //
     45 // Use of NonDereferenceable is required to avoid errors from sanitization tools
     46 // like `clang++ -fsanitize=vptr`, and should prevent false positives while
     47 // pointers are manipulated within NonDereferenceable objects.
     48 //
     49 template <typename T>
     50 class NonDereferenceable {
     51 public:
     52  // Default construction with a null value.
     53  NonDereferenceable() : mPtr(nullptr) {}
     54 
     55  // Default copy construction and assignment.
     56  NO_POINTEE_CHECKS
     57  NonDereferenceable(const NonDereferenceable&) = default;
     58  NO_POINTEE_CHECKS
     59  NonDereferenceable<T>& operator=(const NonDereferenceable&) = default;
     60  // No move operations, as we're only carrying a non-owning pointer, so
     61  // copying is most efficient.
     62 
     63  // Construct/assign from a T* raw pointer.
     64  // A raw pointer should usually point at a valid object, however we want to
     65  // leave the ability to the user to create a NonDereferenceable from any
     66  // pointer. Also, strictly speaking, in a constructor or destructor, `this`
     67  // points at an object still being constructed or already partially
     68  // destructed, which some very sensitive sanitizers could complain about.
     69  NO_POINTEE_CHECKS
     70  explicit NonDereferenceable(T* aPtr) : mPtr(aPtr) {}
     71  NO_POINTEE_CHECKS
     72  NonDereferenceable& operator=(T* aPtr) {
     73    mPtr = aPtr;
     74    return *this;
     75  }
     76 
     77  // Construct/assign from a compatible pointer type.
     78  template <typename U>
     79  NO_POINTEE_CHECKS explicit NonDereferenceable(U* aOther)
     80      : mPtr(static_cast<T*>(aOther)) {}
     81  template <typename U>
     82  NO_POINTEE_CHECKS NonDereferenceable& operator=(U* aOther) {
     83    mPtr = static_cast<T*>(aOther);
     84    return *this;
     85  }
     86 
     87  // Construct/assign from a NonDereferenceable with a compatible pointer type.
     88  template <typename U>
     89  NO_POINTEE_CHECKS MOZ_IMPLICIT
     90  NonDereferenceable(const NonDereferenceable<U>& aOther)
     91      : mPtr(static_cast<T*>(aOther.mPtr)) {}
     92  template <typename U>
     93  NO_POINTEE_CHECKS NonDereferenceable& operator=(
     94      const NonDereferenceable<U>& aOther) {
     95    mPtr = static_cast<T*>(aOther.mPtr);
     96    return *this;
     97  }
     98 
     99  // Explicitly disallow dereference operators, so that compiler errors point
    100  // at these lines:
    101  T& operator*() = delete;   // Cannot dereference NonDereferenceable!
    102  T* operator->() = delete;  // Cannot dereference NonDereferenceable!
    103 
    104  // Null check.
    105  NO_POINTEE_CHECKS
    106  explicit operator bool() const { return !!mPtr; }
    107 
    108  // Extract the pointer value, untyped.
    109  NO_POINTEE_CHECKS
    110  uintptr_t value() const { return reinterpret_cast<uintptr_t>(mPtr); }
    111 
    112 private:
    113  // Let other NonDereferenceable templates access mPtr, to permit construction/
    114  // assignment from compatible pointer types.
    115  template <typename>
    116  friend class NonDereferenceable;
    117 
    118  T* MOZ_NON_OWNING_REF mPtr;
    119 };
    120 
    121 }  // namespace mozilla
    122 
    123 #undef NO_POINTEE_CHECKS
    124 
    125 #endif /* mozilla_NonDereferenceable_h */