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.

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

mercurial