mfbt/Scoped.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 /* A number of structures to simplify scope-based RAII management. */
     9 #ifndef mozilla_Scoped_h
    10 #define mozilla_Scoped_h
    12 /*
    13  * Resource Acquisition Is Initialization is a programming idiom used
    14  * to write robust code that is able to deallocate resources properly,
    15  * even in presence of execution errors or exceptions that need to be
    16  * propagated.  The Scoped* classes defined in this header perform the
    17  * deallocation of the resource they hold once program execution
    18  * reaches the end of the scope for which they have been defined.
    19  *
    20  * This header provides the following RAII classes:
    21  *
    22  * - |ScopedFreePtr| - a container for a pointer, that automatically calls
    23  *   |free()| at the end of the scope;
    24  * - |ScopedDeletePtr| - a container for a pointer, that automatically calls
    25  *   |delete| at the end of the scope;
    26  * - |ScopedDeleteArray| - a container for a pointer to an array, that
    27  *   automatically calls |delete[]| at the end of the scope.
    28  *
    29  * The general scenario for each of the RAII classes is the following:
    30  *
    31  * ScopedClass foo(create_value());
    32  * // ... In this scope, |foo| is defined. Use |foo.get()| or |foo.rwget()|
    33  *        to access the value.
    34  * // ... In case of |return| or |throw|, |foo| is deallocated automatically.
    35  * // ... If |foo| needs to be returned or stored, use |foo.forget()|
    36  *
    37  * Note that the RAII classes defined in this header do _not_ perform any form
    38  * of reference-counting or garbage-collection. These classes have exactly two
    39  * behaviors:
    40  *
    41  * - if |forget()| has not been called, the resource is always deallocated at
    42  *   the end of the scope;
    43  * - if |forget()| has been called, any control on the resource is unbound
    44  *   and the resource is not deallocated by the class.
    45  *
    46  * Extension:
    47  *
    48  * In addition, this header provides class |Scoped| and macros |SCOPED_TEMPLATE|
    49  * and |MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE|  to simplify the definition
    50  * of RAII classes for other scenarios. These macros have been used to
    51  * automatically close file descriptors/file handles when reaching the end of
    52  * the scope, graphics contexts, etc.
    53  */
    55 #include "mozilla/Assertions.h"
    56 #include "mozilla/Attributes.h"
    57 #include "mozilla/GuardObjects.h"
    58 #include "mozilla/Move.h"
    59 #include "mozilla/NullPtr.h"
    61 namespace mozilla {
    63 /*
    64  * Scoped is a helper to create RAII wrappers
    65  * Type argument |Traits| is expected to have the following structure:
    66  *
    67  *   struct Traits {
    68  *     // Define the type of the value stored in the wrapper
    69  *     typedef value_type type;
    70  *     // Returns the value corresponding to the uninitialized or freed state
    71  *     const static type empty();
    72  *     // Release resources corresponding to the wrapped value
    73  *     // This function is responsible for not releasing an |empty| value
    74  *     const static void release(type);
    75  *   }
    76  */
    77 template<typename Traits>
    78 class Scoped
    79 {
    80   public:
    81     typedef typename Traits::type Resource;
    83     explicit Scoped(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
    84       : value(Traits::empty())
    85     {
    86       MOZ_GUARD_OBJECT_NOTIFIER_INIT;
    87     }
    89     explicit Scoped(const Resource& v
    90                     MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
    91       : value(v)
    92     {
    93       MOZ_GUARD_OBJECT_NOTIFIER_INIT;
    94     }
    96     /* Move constructor. */
    97     explicit Scoped(Scoped&& v
    98                     MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
    99       : value(Move(v.value))
   100     {
   101       MOZ_GUARD_OBJECT_NOTIFIER_INIT;
   102       v.value = Traits::empty();
   103     }
   105     ~Scoped() {
   106       Traits::release(value);
   107     }
   109     // Constant getter
   110     operator const Resource&() const { return value; }
   111     const Resource& operator->() const { return value; }
   112     const Resource& get() const { return value; }
   113     // Non-constant getter.
   114     Resource& rwget() { return value; }
   116     /*
   117      * Forget the resource.
   118      *
   119      * Once |forget| has been called, the |Scoped| is neutralized, i.e. it will
   120      * have no effect at destruction (unless it is reset to another resource by
   121      * |operator=|).
   122      *
   123      * @return The original resource.
   124      */
   125     Resource forget() {
   126       Resource tmp = value;
   127       value = Traits::empty();
   128       return tmp;
   129     }
   131     /*
   132      * Perform immediate clean-up of this |Scoped|.
   133      *
   134      * If this |Scoped| is currently empty, this method has no effect.
   135      */
   136     void dispose() {
   137       Traits::release(value);
   138       value = Traits::empty();
   139     }
   141     bool operator==(const Resource& other) const {
   142       return value == other;
   143     }
   145     /*
   146      * Replace the resource with another resource.
   147      *
   148      * Calling |operator=| has the side-effect of triggering clean-up. If you do
   149      * not want to trigger clean-up, you should first invoke |forget|.
   150      *
   151      * @return this
   152      */
   153     Scoped& operator=(const Resource& other) {
   154       return reset(other);
   155     }
   156     Scoped& reset(const Resource& other) {
   157       Traits::release(value);
   158       value = other;
   159       return *this;
   160     }
   162     /* Move assignment operator. */
   163     Scoped& operator=(Scoped&& rhs) {
   164       MOZ_ASSERT(&rhs != this, "self-move-assignment not allowed");
   165       this->~Scoped();
   166       new(this) Scoped(Move(rhs));
   167       return *this;
   168     }
   170   private:
   171     explicit Scoped(const Scoped& value) MOZ_DELETE;
   172     Scoped& operator=(const Scoped& value) MOZ_DELETE;
   174   private:
   175     Resource value;
   176     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   177 };
   179 /*
   180  * SCOPED_TEMPLATE defines a templated class derived from Scoped
   181  * This allows to implement templates such as ScopedFreePtr.
   182  *
   183  * @param name The name of the class to define.
   184  * @param Traits A struct implementing clean-up. See the implementations
   185  * for more details.
   186  */
   187 #define SCOPED_TEMPLATE(name, Traits)                          \
   188 template<typename Type>                                        \
   189 struct name : public mozilla::Scoped<Traits<Type> >            \
   190 {                                                              \
   191     typedef mozilla::Scoped<Traits<Type> > Super;              \
   192     typedef typename Super::Resource Resource;                 \
   193     name& operator=(Resource rhs) {                            \
   194       Super::operator=(rhs);                                   \
   195       return *this;                                            \
   196     }                                                          \
   197     name& operator=(name&& rhs) {                              \
   198       Super::operator=(Move(rhs));                             \
   199       return *this;                                            \
   200     }                                                          \
   201     explicit name(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)        \
   202       : Super(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT)  \
   203     {}                                                         \
   204     explicit name(Resource rhs                                 \
   205                   MOZ_GUARD_OBJECT_NOTIFIER_PARAM)             \
   206       : Super(rhs                                              \
   207               MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)       \
   208     {}                                                         \
   209     explicit name(name&& rhs                                   \
   210                   MOZ_GUARD_OBJECT_NOTIFIER_PARAM)             \
   211       : Super(Move(rhs)                                        \
   212               MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)       \
   213     {}                                                         \
   214   private:                                                     \
   215     explicit name(name&) MOZ_DELETE;                           \
   216     name& operator=(name&) MOZ_DELETE;                         \
   217 };
   219 /*
   220  * ScopedFreePtr is a RAII wrapper for pointers that need to be free()d.
   221  *
   222  *   struct S { ... };
   223  *   ScopedFreePtr<S> foo = malloc(sizeof(S));
   224  *   ScopedFreePtr<char> bar = strdup(str);
   225  */
   226 template<typename T>
   227 struct ScopedFreePtrTraits
   228 {
   229     typedef T* type;
   230     static T* empty() { return nullptr; }
   231     static void release(T* ptr) { free(ptr); }
   232 };
   233 SCOPED_TEMPLATE(ScopedFreePtr, ScopedFreePtrTraits)
   235 /*
   236  * ScopedDeletePtr is a RAII wrapper for pointers that need to be deleted.
   237  *
   238  *   struct S { ... };
   239  *   ScopedDeletePtr<S> foo = new S();
   240  */
   241 template<typename T>
   242 struct ScopedDeletePtrTraits : public ScopedFreePtrTraits<T>
   243 {
   244     static void release(T* ptr) { delete ptr; }
   245 };
   246 SCOPED_TEMPLATE(ScopedDeletePtr, ScopedDeletePtrTraits)
   248 /*
   249  * ScopedDeleteArray is a RAII wrapper for pointers that need to be delete[]ed.
   250  *
   251  *   struct S { ... };
   252  *   ScopedDeleteArray<S> foo = new S[42];
   253  */
   254 template<typename T>
   255 struct ScopedDeleteArrayTraits : public ScopedFreePtrTraits<T>
   256 {
   257     static void release(T* ptr) { delete [] ptr; }
   258 };
   259 SCOPED_TEMPLATE(ScopedDeleteArray, ScopedDeleteArrayTraits)
   261 /*
   262  * MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE makes it easy to create scoped
   263  * pointers for types with custom deleters; just overload
   264  * TypeSpecificDelete(T*) in the same namespace as T to call the deleter for
   265  * type T.
   266  *
   267  * @param name The name of the class to define.
   268  * @param Type A struct implementing clean-up. See the implementations
   269  * for more details.
   270  * *param Deleter The function that is used to delete/destroy/free a
   271  *        non-null value of Type*.
   272  *
   273  * Example:
   274  *
   275  *   MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, \
   276  *                                             PR_Close)
   277  *   ...
   278  *   {
   279  *       ScopedPRFileDesc file(PR_OpenFile(...));
   280  *       ...
   281  *   } // file is closed with PR_Close here
   282  */
   283 #define MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(name, Type, Deleter) \
   284 template <> inline void TypeSpecificDelete(Type * value) { Deleter(value); } \
   285 typedef ::mozilla::TypeSpecificScopedPointer<Type> name;
   287 template <typename T> void TypeSpecificDelete(T * value);
   289 template <typename T>
   290 struct TypeSpecificScopedPointerTraits
   291 {
   292     typedef T* type;
   293     const static type empty() { return nullptr; }
   294     const static void release(type value)
   295     {
   296       if (value)
   297         TypeSpecificDelete(value);
   298     }
   299 };
   301 SCOPED_TEMPLATE(TypeSpecificScopedPointer, TypeSpecificScopedPointerTraits)
   303 } /* namespace mozilla */
   305 #endif /* mozilla_Scoped_h */

mercurial