mfbt/RangedPtr.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /*
michael@0 8 * Implements a smart pointer asserted to remain within a range specified at
michael@0 9 * construction.
michael@0 10 */
michael@0 11
michael@0 12 #ifndef mozilla_RangedPtr_h
michael@0 13 #define mozilla_RangedPtr_h
michael@0 14
michael@0 15 #include "mozilla/ArrayUtils.h"
michael@0 16 #include "mozilla/Assertions.h"
michael@0 17 #include "mozilla/Attributes.h"
michael@0 18 #include "mozilla/NullPtr.h"
michael@0 19
michael@0 20 #include <stdint.h>
michael@0 21
michael@0 22 namespace mozilla {
michael@0 23
michael@0 24 /*
michael@0 25 * RangedPtr is a smart pointer restricted to an address range specified at
michael@0 26 * creation. The pointer (and any smart pointers derived from it) must remain
michael@0 27 * within the range [start, end] (inclusive of end to facilitate use as
michael@0 28 * sentinels). Dereferencing or indexing into the pointer (or pointers derived
michael@0 29 * from it) must remain within the range [start, end). All the standard pointer
michael@0 30 * operators are defined on it; in debug builds these operations assert that the
michael@0 31 * range specified at construction is respected.
michael@0 32 *
michael@0 33 * In theory passing a smart pointer instance as an argument can be slightly
michael@0 34 * slower than passing a T* (due to ABI requirements for passing structs versus
michael@0 35 * passing pointers), if the method being called isn't inlined. If you are in
michael@0 36 * extremely performance-critical code, you may want to be careful using this
michael@0 37 * smart pointer as an argument type.
michael@0 38 *
michael@0 39 * RangedPtr<T> intentionally does not implicitly convert to T*. Use get() to
michael@0 40 * explicitly convert to T*. Keep in mind that the raw pointer of course won't
michael@0 41 * implement bounds checking in debug builds.
michael@0 42 */
michael@0 43 template<typename T>
michael@0 44 class RangedPtr
michael@0 45 {
michael@0 46 T* ptr;
michael@0 47
michael@0 48 #ifdef DEBUG
michael@0 49 T* const rangeStart;
michael@0 50 T* const rangeEnd;
michael@0 51 #endif
michael@0 52
michael@0 53 typedef void (RangedPtr::* ConvertibleToBool)();
michael@0 54 void nonNull() {}
michael@0 55
michael@0 56 void checkSanity() {
michael@0 57 MOZ_ASSERT(rangeStart <= ptr);
michael@0 58 MOZ_ASSERT(ptr <= rangeEnd);
michael@0 59 }
michael@0 60
michael@0 61 /* Creates a new pointer for |p|, restricted to this pointer's range. */
michael@0 62 RangedPtr<T> create(T *p) const {
michael@0 63 #ifdef DEBUG
michael@0 64 return RangedPtr<T>(p, rangeStart, rangeEnd);
michael@0 65 #else
michael@0 66 return RangedPtr<T>(p, nullptr, size_t(0));
michael@0 67 #endif
michael@0 68 }
michael@0 69
michael@0 70 uintptr_t asUintptr() const { return uintptr_t(ptr); }
michael@0 71
michael@0 72 public:
michael@0 73 RangedPtr(T* p, T* start, T* end)
michael@0 74 : ptr(p)
michael@0 75 #ifdef DEBUG
michael@0 76 , rangeStart(start), rangeEnd(end)
michael@0 77 #endif
michael@0 78 {
michael@0 79 MOZ_ASSERT(rangeStart <= rangeEnd);
michael@0 80 checkSanity();
michael@0 81 }
michael@0 82 RangedPtr(T* p, T* start, size_t length)
michael@0 83 : ptr(p)
michael@0 84 #ifdef DEBUG
michael@0 85 , rangeStart(start), rangeEnd(start + length)
michael@0 86 #endif
michael@0 87 {
michael@0 88 MOZ_ASSERT(length <= size_t(-1) / sizeof(T));
michael@0 89 MOZ_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart));
michael@0 90 checkSanity();
michael@0 91 }
michael@0 92
michael@0 93 /* Equivalent to RangedPtr(p, p, length). */
michael@0 94 RangedPtr(T* p, size_t length)
michael@0 95 : ptr(p)
michael@0 96 #ifdef DEBUG
michael@0 97 , rangeStart(p), rangeEnd(p + length)
michael@0 98 #endif
michael@0 99 {
michael@0 100 MOZ_ASSERT(length <= size_t(-1) / sizeof(T));
michael@0 101 MOZ_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart));
michael@0 102 checkSanity();
michael@0 103 }
michael@0 104
michael@0 105 /* Equivalent to RangedPtr(arr, arr, N). */
michael@0 106 template<size_t N>
michael@0 107 RangedPtr(T (&arr)[N])
michael@0 108 : ptr(arr)
michael@0 109 #ifdef DEBUG
michael@0 110 , rangeStart(arr), rangeEnd(arr + N)
michael@0 111 #endif
michael@0 112 {
michael@0 113 checkSanity();
michael@0 114 }
michael@0 115
michael@0 116 T* get() const {
michael@0 117 return ptr;
michael@0 118 }
michael@0 119
michael@0 120 operator ConvertibleToBool() const { return ptr ? &RangedPtr::nonNull : 0; }
michael@0 121
michael@0 122 /*
michael@0 123 * You can only assign one RangedPtr into another if the two pointers have
michael@0 124 * the same valid range:
michael@0 125 *
michael@0 126 * char arr1[] = "hi";
michael@0 127 * char arr2[] = "bye";
michael@0 128 * RangedPtr<char> p1(arr1, 2);
michael@0 129 * p1 = RangedPtr<char>(arr1 + 1, arr1, arr1 + 2); // works
michael@0 130 * p1 = RangedPtr<char>(arr2, 3); // asserts
michael@0 131 */
michael@0 132 RangedPtr<T>& operator=(const RangedPtr<T>& other) {
michael@0 133 MOZ_ASSERT(rangeStart == other.rangeStart);
michael@0 134 MOZ_ASSERT(rangeEnd == other.rangeEnd);
michael@0 135 ptr = other.ptr;
michael@0 136 checkSanity();
michael@0 137 return *this;
michael@0 138 }
michael@0 139
michael@0 140 RangedPtr<T> operator+(size_t inc) {
michael@0 141 MOZ_ASSERT(inc <= size_t(-1) / sizeof(T));
michael@0 142 MOZ_ASSERT(asUintptr() + inc * sizeof(T) >= asUintptr());
michael@0 143 return create(ptr + inc);
michael@0 144 }
michael@0 145
michael@0 146 RangedPtr<T> operator-(size_t dec) {
michael@0 147 MOZ_ASSERT(dec <= size_t(-1) / sizeof(T));
michael@0 148 MOZ_ASSERT(asUintptr() - dec * sizeof(T) <= asUintptr());
michael@0 149 return create(ptr - dec);
michael@0 150 }
michael@0 151
michael@0 152 /*
michael@0 153 * You can assign a raw pointer into a RangedPtr if the raw pointer is
michael@0 154 * within the range specified at creation.
michael@0 155 */
michael@0 156 template <typename U>
michael@0 157 RangedPtr<T>& operator=(U* p) {
michael@0 158 *this = create(p);
michael@0 159 return *this;
michael@0 160 }
michael@0 161
michael@0 162 template <typename U>
michael@0 163 RangedPtr<T>& operator=(const RangedPtr<U>& p) {
michael@0 164 MOZ_ASSERT(rangeStart <= p.ptr);
michael@0 165 MOZ_ASSERT(p.ptr <= rangeEnd);
michael@0 166 ptr = p.ptr;
michael@0 167 checkSanity();
michael@0 168 return *this;
michael@0 169 }
michael@0 170
michael@0 171 RangedPtr<T>& operator++() {
michael@0 172 return (*this += 1);
michael@0 173 }
michael@0 174
michael@0 175 RangedPtr<T> operator++(int) {
michael@0 176 RangedPtr<T> rcp = *this;
michael@0 177 ++*this;
michael@0 178 return rcp;
michael@0 179 }
michael@0 180
michael@0 181 RangedPtr<T>& operator--() {
michael@0 182 return (*this -= 1);
michael@0 183 }
michael@0 184
michael@0 185 RangedPtr<T> operator--(int) {
michael@0 186 RangedPtr<T> rcp = *this;
michael@0 187 --*this;
michael@0 188 return rcp;
michael@0 189 }
michael@0 190
michael@0 191 RangedPtr<T>& operator+=(size_t inc) {
michael@0 192 *this = *this + inc;
michael@0 193 return *this;
michael@0 194 }
michael@0 195
michael@0 196 RangedPtr<T>& operator-=(size_t dec) {
michael@0 197 *this = *this - dec;
michael@0 198 return *this;
michael@0 199 }
michael@0 200
michael@0 201 T& operator[](int index) const {
michael@0 202 MOZ_ASSERT(size_t(index > 0 ? index : -index) <= size_t(-1) / sizeof(T));
michael@0 203 return *create(ptr + index);
michael@0 204 }
michael@0 205
michael@0 206 T& operator*() const {
michael@0 207 MOZ_ASSERT(ptr >= rangeStart);
michael@0 208 MOZ_ASSERT(ptr < rangeEnd);
michael@0 209 return *ptr;
michael@0 210 }
michael@0 211
michael@0 212 template <typename U>
michael@0 213 bool operator==(const RangedPtr<U>& other) const {
michael@0 214 return ptr == other.ptr;
michael@0 215 }
michael@0 216 template <typename U>
michael@0 217 bool operator!=(const RangedPtr<U>& other) const {
michael@0 218 return !(*this == other);
michael@0 219 }
michael@0 220
michael@0 221 template<typename U>
michael@0 222 bool operator==(const U* u) const {
michael@0 223 return ptr == u;
michael@0 224 }
michael@0 225 template<typename U>
michael@0 226 bool operator!=(const U* u) const {
michael@0 227 return !(*this == u);
michael@0 228 }
michael@0 229
michael@0 230 template <typename U>
michael@0 231 bool operator<(const RangedPtr<U>& other) const {
michael@0 232 return ptr < other.ptr;
michael@0 233 }
michael@0 234 template <typename U>
michael@0 235 bool operator<=(const RangedPtr<U>& other) const {
michael@0 236 return ptr <= other.ptr;
michael@0 237 }
michael@0 238
michael@0 239 template <typename U>
michael@0 240 bool operator>(const RangedPtr<U>& other) const {
michael@0 241 return ptr > other.ptr;
michael@0 242 }
michael@0 243 template <typename U>
michael@0 244 bool operator>=(const RangedPtr<U>& other) const {
michael@0 245 return ptr >= other.ptr;
michael@0 246 }
michael@0 247
michael@0 248 size_t operator-(const RangedPtr<T>& other) const {
michael@0 249 MOZ_ASSERT(ptr >= other.ptr);
michael@0 250 return PointerRangeSize(other.ptr, ptr);
michael@0 251 }
michael@0 252
michael@0 253 private:
michael@0 254 RangedPtr() MOZ_DELETE;
michael@0 255 T* operator&() MOZ_DELETE;
michael@0 256 };
michael@0 257
michael@0 258 } /* namespace mozilla */
michael@0 259
michael@0 260 #endif /* mozilla_RangedPtr_h */

mercurial