Tue, 06 Jan 2015 21:39:09 +0100
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 | * Operations for zeroing POD types, arrays, and so on. |
michael@0 | 9 | * |
michael@0 | 10 | * These operations are preferable to memset, memcmp, and the like because they |
michael@0 | 11 | * don't require remembering to multiply by sizeof(T), array lengths, and so on |
michael@0 | 12 | * everywhere. |
michael@0 | 13 | */ |
michael@0 | 14 | |
michael@0 | 15 | #ifndef mozilla_PodOperations_h |
michael@0 | 16 | #define mozilla_PodOperations_h |
michael@0 | 17 | |
michael@0 | 18 | #include "mozilla/Array.h" |
michael@0 | 19 | #include "mozilla/ArrayUtils.h" |
michael@0 | 20 | #include "mozilla/Attributes.h" |
michael@0 | 21 | |
michael@0 | 22 | #include <stdint.h> |
michael@0 | 23 | #include <string.h> |
michael@0 | 24 | |
michael@0 | 25 | namespace mozilla { |
michael@0 | 26 | |
michael@0 | 27 | /** Set the contents of |t| to 0. */ |
michael@0 | 28 | template<typename T> |
michael@0 | 29 | static MOZ_ALWAYS_INLINE void |
michael@0 | 30 | PodZero(T* t) |
michael@0 | 31 | { |
michael@0 | 32 | memset(t, 0, sizeof(T)); |
michael@0 | 33 | } |
michael@0 | 34 | |
michael@0 | 35 | /** Set the contents of |nelem| elements starting at |t| to 0. */ |
michael@0 | 36 | template<typename T> |
michael@0 | 37 | static MOZ_ALWAYS_INLINE void |
michael@0 | 38 | PodZero(T* t, size_t nelem) |
michael@0 | 39 | { |
michael@0 | 40 | /* |
michael@0 | 41 | * This function is often called with 'nelem' small; we use an inline loop |
michael@0 | 42 | * instead of calling 'memset' with a non-constant length. The compiler |
michael@0 | 43 | * should inline the memset call with constant size, though. |
michael@0 | 44 | */ |
michael@0 | 45 | for (T* end = t + nelem; t < end; t++) |
michael@0 | 46 | memset(t, 0, sizeof(T)); |
michael@0 | 47 | } |
michael@0 | 48 | |
michael@0 | 49 | /* |
michael@0 | 50 | * Arrays implicitly convert to pointers to their first element, which is |
michael@0 | 51 | * dangerous when combined with the above PodZero definitions. Adding an |
michael@0 | 52 | * overload for arrays is ambiguous, so we need another identifier. The |
michael@0 | 53 | * ambiguous overload is left to catch mistaken uses of PodZero; if you get a |
michael@0 | 54 | * compile error involving PodZero and array types, use PodArrayZero instead. |
michael@0 | 55 | */ |
michael@0 | 56 | template<typename T, size_t N> |
michael@0 | 57 | static void PodZero(T (&t)[N]) MOZ_DELETE; |
michael@0 | 58 | template<typename T, size_t N> |
michael@0 | 59 | static void PodZero(T (&t)[N], size_t nelem) MOZ_DELETE; |
michael@0 | 60 | |
michael@0 | 61 | /** Set the contents of the array |t| to zero. */ |
michael@0 | 62 | template <class T, size_t N> |
michael@0 | 63 | static MOZ_ALWAYS_INLINE void |
michael@0 | 64 | PodArrayZero(T (&t)[N]) |
michael@0 | 65 | { |
michael@0 | 66 | memset(t, 0, N * sizeof(T)); |
michael@0 | 67 | } |
michael@0 | 68 | |
michael@0 | 69 | template <typename T, size_t N> |
michael@0 | 70 | static MOZ_ALWAYS_INLINE void |
michael@0 | 71 | PodArrayZero(Array<T, N>& arr) |
michael@0 | 72 | { |
michael@0 | 73 | memset(&arr[0], 0, N * sizeof(T)); |
michael@0 | 74 | } |
michael@0 | 75 | |
michael@0 | 76 | /** |
michael@0 | 77 | * Assign |*src| to |*dst|. The locations must not be the same and must not |
michael@0 | 78 | * overlap. |
michael@0 | 79 | */ |
michael@0 | 80 | template<typename T> |
michael@0 | 81 | static MOZ_ALWAYS_INLINE void |
michael@0 | 82 | PodAssign(T* dst, const T* src) |
michael@0 | 83 | { |
michael@0 | 84 | MOZ_ASSERT(dst != src); |
michael@0 | 85 | MOZ_ASSERT_IF(src < dst, PointerRangeSize(src, static_cast<const T*>(dst)) >= 1); |
michael@0 | 86 | MOZ_ASSERT_IF(dst < src, PointerRangeSize(static_cast<const T*>(dst), src) >= 1); |
michael@0 | 87 | memcpy(reinterpret_cast<char*>(dst), reinterpret_cast<const char*>(src), sizeof(T)); |
michael@0 | 88 | } |
michael@0 | 89 | |
michael@0 | 90 | /** |
michael@0 | 91 | * Copy |nelem| T elements from |src| to |dst|. The two memory ranges must not |
michael@0 | 92 | * overlap! |
michael@0 | 93 | */ |
michael@0 | 94 | template<typename T> |
michael@0 | 95 | static MOZ_ALWAYS_INLINE void |
michael@0 | 96 | PodCopy(T* dst, const T* src, size_t nelem) |
michael@0 | 97 | { |
michael@0 | 98 | MOZ_ASSERT(dst != src); |
michael@0 | 99 | MOZ_ASSERT_IF(src < dst, PointerRangeSize(src, static_cast<const T*>(dst)) >= nelem); |
michael@0 | 100 | MOZ_ASSERT_IF(dst < src, PointerRangeSize(static_cast<const T*>(dst), src) >= nelem); |
michael@0 | 101 | |
michael@0 | 102 | if (nelem < 128) { |
michael@0 | 103 | /* |
michael@0 | 104 | * Avoid using operator= in this loop, as it may have been |
michael@0 | 105 | * intentionally deleted by the POD type. |
michael@0 | 106 | */ |
michael@0 | 107 | for (const T* srcend = src + nelem; src < srcend; src++, dst++) |
michael@0 | 108 | PodAssign(dst, src); |
michael@0 | 109 | } else { |
michael@0 | 110 | memcpy(dst, src, nelem * sizeof(T)); |
michael@0 | 111 | } |
michael@0 | 112 | } |
michael@0 | 113 | |
michael@0 | 114 | template<typename T> |
michael@0 | 115 | static MOZ_ALWAYS_INLINE void |
michael@0 | 116 | PodCopy(volatile T* dst, const volatile T* src, size_t nelem) |
michael@0 | 117 | { |
michael@0 | 118 | MOZ_ASSERT(dst != src); |
michael@0 | 119 | MOZ_ASSERT_IF(src < dst, |
michael@0 | 120 | PointerRangeSize(src, static_cast<const volatile T*>(dst)) >= nelem); |
michael@0 | 121 | MOZ_ASSERT_IF(dst < src, |
michael@0 | 122 | PointerRangeSize(static_cast<const volatile T*>(dst), src) >= nelem); |
michael@0 | 123 | |
michael@0 | 124 | /* |
michael@0 | 125 | * Volatile |dst| requires extra work, because it's undefined behavior to |
michael@0 | 126 | * modify volatile objects using the mem* functions. Just write out the |
michael@0 | 127 | * loops manually, using operator= rather than memcpy for the same reason, |
michael@0 | 128 | * and let the compiler optimize to the extent it can. |
michael@0 | 129 | */ |
michael@0 | 130 | for (const volatile T* srcend = src + nelem; src < srcend; src++, dst++) |
michael@0 | 131 | *dst = *src; |
michael@0 | 132 | } |
michael@0 | 133 | |
michael@0 | 134 | /* |
michael@0 | 135 | * Copy the contents of the array |src| into the array |dst|, both of size N. |
michael@0 | 136 | * The arrays must not overlap! |
michael@0 | 137 | */ |
michael@0 | 138 | template <class T, size_t N> |
michael@0 | 139 | static MOZ_ALWAYS_INLINE void |
michael@0 | 140 | PodArrayCopy(T (&dst)[N], const T (&src)[N]) |
michael@0 | 141 | { |
michael@0 | 142 | PodCopy(dst, src, N); |
michael@0 | 143 | } |
michael@0 | 144 | |
michael@0 | 145 | /** |
michael@0 | 146 | * Copy the memory for |nelem| T elements from |src| to |dst|. If the two |
michael@0 | 147 | * memory ranges overlap, then the effect is as if the |nelem| elements are |
michael@0 | 148 | * first copied from |src| to a temporary array, and then from the temporary |
michael@0 | 149 | * array to |dst|. |
michael@0 | 150 | */ |
michael@0 | 151 | template<typename T> |
michael@0 | 152 | static MOZ_ALWAYS_INLINE void |
michael@0 | 153 | PodMove(T* dst, const T* src, size_t nelem) |
michael@0 | 154 | { |
michael@0 | 155 | MOZ_ASSERT(nelem <= SIZE_MAX / sizeof(T), |
michael@0 | 156 | "trying to move an impossible number of elements"); |
michael@0 | 157 | memmove(dst, src, nelem * sizeof(T)); |
michael@0 | 158 | } |
michael@0 | 159 | |
michael@0 | 160 | /** |
michael@0 | 161 | * Determine whether the |len| elements at |one| are memory-identical to the |
michael@0 | 162 | * |len| elements at |two|. |
michael@0 | 163 | */ |
michael@0 | 164 | template<typename T> |
michael@0 | 165 | static MOZ_ALWAYS_INLINE bool |
michael@0 | 166 | PodEqual(const T* one, const T* two, size_t len) |
michael@0 | 167 | { |
michael@0 | 168 | if (len < 128) { |
michael@0 | 169 | const T* p1end = one + len; |
michael@0 | 170 | const T* p1 = one; |
michael@0 | 171 | const T* p2 = two; |
michael@0 | 172 | for (; p1 < p1end; p1++, p2++) { |
michael@0 | 173 | if (*p1 != *p2) |
michael@0 | 174 | return false; |
michael@0 | 175 | } |
michael@0 | 176 | return true; |
michael@0 | 177 | } |
michael@0 | 178 | |
michael@0 | 179 | return !memcmp(one, two, len * sizeof(T)); |
michael@0 | 180 | } |
michael@0 | 181 | |
michael@0 | 182 | } // namespace mozilla |
michael@0 | 183 | |
michael@0 | 184 | #endif /* mozilla_PodOperations_h */ |