mfbt/Casting.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 /* Cast operations to supplement the built-in casting operations. */
     9 #ifndef mozilla_Casting_h
    10 #define mozilla_Casting_h
    12 #include "mozilla/Assertions.h"
    13 #include "mozilla/TypeTraits.h"
    15 #include <limits.h>
    17 namespace mozilla {
    19 /**
    20  * Return a value of type |To|, containing the underlying bit pattern of |from|.
    21  *
    22  * |To| and |From| must be types of the same size; be careful of cross-platform
    23  * size differences, or this might fail to compile on some but not all
    24  * platforms.
    25  */
    26 template<typename To, typename From>
    27 inline To
    28 BitwiseCast(const From from)
    29 {
    30   static_assert(sizeof(From) == sizeof(To),
    31                 "To and From must have the same size");
    32   union {
    33     From from;
    34     To to;
    35   } u;
    36   u.from = from;
    37   return u.to;
    38 }
    40 namespace detail {
    42 enum ToSignedness { ToIsSigned, ToIsUnsigned };
    43 enum FromSignedness { FromIsSigned, FromIsUnsigned };
    45 template<typename From,
    46          typename To,
    47          FromSignedness = IsSigned<From>::value ? FromIsSigned : FromIsUnsigned,
    48          ToSignedness = IsSigned<To>::value ? ToIsSigned : ToIsUnsigned>
    49 struct BoundsCheckImpl;
    51 // Implicit conversions on operands to binary operations make this all a bit
    52 // hard to verify.  Attempt to ease the pain below by *only* comparing values
    53 // that are obviously the same type (and will undergo no further conversions),
    54 // even when it's not strictly necessary, for explicitness.
    56 enum UUComparison { FromIsBigger, FromIsNotBigger };
    58 // Unsigned-to-unsigned range check
    60 template<typename From, typename To,
    61          UUComparison = (sizeof(From) > sizeof(To)) ? FromIsBigger : FromIsNotBigger>
    62 struct UnsignedUnsignedCheck;
    64 template<typename From, typename To>
    65 struct UnsignedUnsignedCheck<From, To, FromIsBigger>
    66 {
    67   public:
    68     static bool checkBounds(const From from) {
    69       return from <= From(To(-1));
    70     }
    71 };
    73 template<typename From, typename To>
    74 struct UnsignedUnsignedCheck<From, To, FromIsNotBigger>
    75 {
    76   public:
    77     static bool checkBounds(const From from) {
    78       return true;
    79     }
    80 };
    82 template<typename From, typename To>
    83 struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsUnsigned>
    84 {
    85   public:
    86     static bool checkBounds(const From from) {
    87       return UnsignedUnsignedCheck<From, To>::checkBounds(from);
    88     }
    89 };
    91 // Signed-to-unsigned range check
    93 template<typename From, typename To>
    94 struct BoundsCheckImpl<From, To, FromIsSigned, ToIsUnsigned>
    95 {
    96   public:
    97     static bool checkBounds(const From from) {
    98       if (from < 0)
    99         return false;
   100       if (sizeof(To) >= sizeof(From))
   101         return true;
   102       return from <= From(To(-1));
   103     }
   104 };
   106 // Unsigned-to-signed range check
   108 enum USComparison { FromIsSmaller, FromIsNotSmaller };
   110 template<typename From, typename To,
   111          USComparison = (sizeof(From) < sizeof(To)) ? FromIsSmaller : FromIsNotSmaller>
   112 struct UnsignedSignedCheck;
   114 template<typename From, typename To>
   115 struct UnsignedSignedCheck<From, To, FromIsSmaller>
   116 {
   117   public:
   118     static bool checkBounds(const From from) {
   119       return true;
   120     }
   121 };
   123 template<typename From, typename To>
   124 struct UnsignedSignedCheck<From, To, FromIsNotSmaller>
   125 {
   126   public:
   127     static bool checkBounds(const From from) {
   128       const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1);
   129       return from <= From(MaxValue);
   130     }
   131 };
   133 template<typename From, typename To>
   134 struct BoundsCheckImpl<From, To, FromIsUnsigned, ToIsSigned>
   135 {
   136   public:
   137     static bool checkBounds(const From from) {
   138       return UnsignedSignedCheck<From, To>::checkBounds(from);
   139     }
   140 };
   142 // Signed-to-signed range check
   144 template<typename From, typename To>
   145 struct BoundsCheckImpl<From, To, FromIsSigned, ToIsSigned>
   146 {
   147   public:
   148     static bool checkBounds(const From from) {
   149       if (sizeof(From) <= sizeof(To))
   150         return true;
   151       const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1);
   152       const To MinValue = -MaxValue - To(1);
   153       return From(MinValue) <= from &&
   154              From(from) <= From(MaxValue);
   155     }
   156 };
   158 template<typename From, typename To,
   159          bool TypesAreIntegral = IsIntegral<From>::value && IsIntegral<To>::value>
   160 class BoundsChecker;
   162 template<typename From>
   163 class BoundsChecker<From, From, true>
   164 {
   165   public:
   166     static bool checkBounds(const From from) { return true; }
   167 };
   169 template<typename From, typename To>
   170 class BoundsChecker<From, To, true>
   171 {
   172   public:
   173     static bool checkBounds(const From from) {
   174       return BoundsCheckImpl<From, To>::checkBounds(from);
   175     }
   176 };
   178 template<typename From, typename To>
   179 inline bool
   180 IsInBounds(const From from)
   181 {
   182   return BoundsChecker<From, To>::checkBounds(from);
   183 }
   185 } // namespace detail
   187 /**
   188  * Cast a value of integral type |From| to a value of integral type |To|,
   189  * asserting that the cast will be a safe cast per C++ (that is, that |to| is in
   190  * the range of values permitted for the type |From|).
   191  */
   192 template<typename To, typename From>
   193 inline To
   194 SafeCast(const From from)
   195 {
   196   MOZ_ASSERT((detail::IsInBounds<From, To>(from)));
   197   return static_cast<To>(from);
   198 }
   200 } // namespace mozilla
   202 #endif /* mozilla_Casting_h */

mercurial