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/. */
7 #ifndef mozilla_NonDereferenceable_h
8 #define mozilla_NonDereferenceable_h
10 /* A pointer wrapper indicating that the pointer should not be dereferenced. */
12 #include "mozilla/Attributes.h"
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")))
21 # define NO_POINTEE_CHECKS /* nothing */
26 // NonDereferenceable<T> wraps a raw pointer value of type T*, but prevents
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.
38 // Note that NonDereferenceable is only a wrapper and is NOT an owning pointer,
39 // i.e., it will not release/free the object.
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.
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.
50 class NonDereferenceable
{
52 // Default construction with a null value.
53 NonDereferenceable() : mPtr(nullptr) {}
55 // Default copy construction and assignment.
57 NonDereferenceable(const NonDereferenceable
&) = default;
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.
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.
70 explicit NonDereferenceable(T
* aPtr
) : mPtr(aPtr
) {}
72 NonDereferenceable
& operator=(T
* aPtr
) {
77 // Construct/assign from a compatible pointer type.
79 NO_POINTEE_CHECKS
explicit NonDereferenceable(U
* aOther
)
80 : mPtr(static_cast<T
*>(aOther
)) {}
82 NO_POINTEE_CHECKS NonDereferenceable
& operator=(U
* aOther
) {
83 mPtr
= static_cast<T
*>(aOther
);
87 // Construct/assign from a NonDereferenceable with a compatible pointer type.
89 NO_POINTEE_CHECKS MOZ_IMPLICIT
90 NonDereferenceable(const NonDereferenceable
<U
>& aOther
)
91 : mPtr(static_cast<T
*>(aOther
.mPtr
)) {}
93 NO_POINTEE_CHECKS NonDereferenceable
& operator=(
94 const NonDereferenceable
<U
>& aOther
) {
95 mPtr
= static_cast<T
*>(aOther
.mPtr
);
99 // Explicitly disallow dereference operators, so that compiler errors point
101 T
& operator*() = delete; // Cannot dereference NonDereferenceable!
102 T
* operator->() = delete; // Cannot dereference NonDereferenceable!
106 explicit operator bool() const { return !!mPtr
; }
108 // Extract the pointer value, untyped.
110 uintptr_t value() const { return reinterpret_cast<uintptr_t>(mPtr
); }
113 // Let other NonDereferenceable templates access mPtr, to permit construction/
114 // assignment from compatible pointer types.
116 friend class NonDereferenceable
;
118 T
* MOZ_NON_OWNING_REF mPtr
;
121 } // namespace mozilla
123 #undef NO_POINTEE_CHECKS
125 #endif /* mozilla_NonDereferenceable_h */