LCOV - code coverage report
Current view: top level - mfbt - GuardObjects.h (source / functions) Hit Total Coverage
Test: output.info Lines: 18 18 100.0 %
Date: 2017-07-14 16:53:18 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : /* Implementation of macros to ensure correct use of RAII Auto* objects. */
       8             : 
       9             : #ifndef mozilla_GuardObjects_h
      10             : #define mozilla_GuardObjects_h
      11             : 
      12             : #include "mozilla/Assertions.h"
      13             : #include "mozilla/Move.h"
      14             : #include "mozilla/Types.h"
      15             : 
      16             : #ifdef __cplusplus
      17             : 
      18             : #ifdef DEBUG
      19             : 
      20             : /**
      21             :  * A custom define is used rather than |mozPoisonValue()| due to cascading
      22             :  * build failures relating to how mfbt is linked on different operating
      23             :  * systems. See bug 1160253.
      24             :  */
      25             : #define MOZ_POISON uintptr_t(-1)
      26             : 
      27             : namespace mozilla {
      28             : namespace detail {
      29             : 
      30             : /*
      31             :  * The following classes are designed to cause assertions to detect
      32             :  * inadvertent use of guard objects as temporaries. In other words,
      33             :  * when we have a guard object whose only purpose is its constructor and
      34             :  * destructor (and is never otherwise referenced), the intended use
      35             :  * might be:
      36             :  *
      37             :  *   AutoRestore savePainting(mIsPainting);
      38             :  *
      39             :  * but is is easy to accidentally write:
      40             :  *
      41             :  *   AutoRestore(mIsPainting);
      42             :  *
      43             :  * which compiles just fine, but runs the destructor well before the
      44             :  * intended time.
      45             :  *
      46             :  * They work by adding (#ifdef DEBUG) an additional parameter to the
      47             :  * guard object's constructor, with a default value, so that users of
      48             :  * the guard object's API do not need to do anything. The default value
      49             :  * of this parameter is a temporary object. C++ (ISO/IEC 14882:1998),
      50             :  * section 12.2 [class.temporary], clauses 4 and 5 seem to assume a
      51             :  * guarantee that temporaries are destroyed in the reverse of their
      52             :  * construction order, but I actually can't find a statement that that
      53             :  * is true in the general case (beyond the two specific cases mentioned
      54             :  * there). However, it seems to be true.
      55             :  *
      56             :  * These classes are intended to be used only via the macros immediately
      57             :  * below them:
      58             :  *
      59             :  *   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER declares (ifdef DEBUG) a member
      60             :  *     variable, and should be put where a declaration of a private
      61             :  *     member variable would be placed.
      62             :  *   MOZ_GUARD_OBJECT_NOTIFIER_PARAM should be placed at the end of the
      63             :  *     parameters to each constructor of the guard object; it declares
      64             :  *     (ifdef DEBUG) an additional parameter. (But use the *_ONLY_PARAM
      65             :  *     variant for constructors that take no other parameters.)
      66             :  *   MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL should likewise be used in
      67             :  *     the implementation of such constructors when they are not inline.
      68             :  *   MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT should be used in
      69             :  *     the implementation of such constructors to pass the parameter to
      70             :  *     a base class that also uses these macros
      71             :  *   MOZ_GUARD_OBJECT_NOTIFIER_INIT is a statement that belongs in each
      72             :  *     constructor. It uses the parameter declared by
      73             :  *     MOZ_GUARD_OBJECT_NOTIFIER_PARAM.
      74             :  *
      75             :  * For more details, and examples of using these macros, see
      76             :  * https://developer.mozilla.org/en/Using_RAII_classes_in_Mozilla
      77             :  */
      78             : class GuardObjectNotifier
      79             : {
      80             : private:
      81             :   bool* mStatementDone;
      82             : 
      83             : public:
      84    10780813 :   GuardObjectNotifier()
      85    10780813 :     : mStatementDone(reinterpret_cast<bool*>(MOZ_POISON))
      86             :   {
      87    10780813 :   }
      88             : 
      89    10779500 :   ~GuardObjectNotifier()
      90    10779500 :   {
      91             :     // Assert that the GuardObjectNotifier has been properly initialized by
      92             :     // using the |MOZ_GUARD_OBJECT_NOTIFIER_INIT| macro. A poison value is
      93             :     // used rather than a null check to appease static analyzers that were
      94             :     // (incorrectly) detecting null pointer dereferences.
      95    10779500 :     MOZ_ASSERT(mStatementDone != reinterpret_cast<bool*>(MOZ_POISON));
      96    10779500 :     *mStatementDone = true;
      97    10779500 :   }
      98             : 
      99    10778545 :   void setStatementDone(bool* aStatementIsDone)
     100             :   {
     101    10778545 :     mStatementDone = aStatementIsDone;
     102    10778545 :   }
     103             : };
     104             : 
     105             : class GuardObjectNotificationReceiver
     106             : {
     107             : private:
     108             :   bool mStatementDone;
     109             : 
     110             : public:
     111    10779070 :   GuardObjectNotificationReceiver() : mStatementDone(false) { }
     112             : 
     113    21564174 :   ~GuardObjectNotificationReceiver() {
     114             :     /*
     115             :      * Assert that the guard object was not used as a temporary.  (Note that
     116             :      * this assert might also fire if init is not called because the guard
     117             :      * object's implementation is not using the above macros correctly.)
     118             :      */
     119    10782087 :     MOZ_ASSERT(mStatementDone);
     120    10782087 :   }
     121             : 
     122    10778783 :   void init(GuardObjectNotifier& aNotifier)
     123             :   {
     124    10778783 :     aNotifier.setStatementDone(&mStatementDone);
     125    10780245 :   }
     126             : };
     127             : 
     128             : } /* namespace detail */
     129             : } /* namespace mozilla */
     130             : 
     131             : #undef MOZ_POISON
     132             : 
     133             : #endif /* DEBUG */
     134             : 
     135             : #ifdef DEBUG
     136             : #  define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER \
     137             :      mozilla::detail::GuardObjectNotificationReceiver _mCheckNotUsedAsTemporary;
     138             : #  define MOZ_GUARD_OBJECT_NOTIFIER_PARAM \
     139             :      , mozilla::detail::GuardObjectNotifier&& _notifier = \
     140             :          mozilla::detail::GuardObjectNotifier()
     141             : #  define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM \
     142             :      mozilla::detail::GuardObjectNotifier&& _notifier = \
     143             :          mozilla::detail::GuardObjectNotifier()
     144             : #  define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL \
     145             :      , mozilla::detail::GuardObjectNotifier&& _notifier
     146             : #  define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL \
     147             :      mozilla::detail::GuardObjectNotifier&& _notifier
     148             : #  define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT \
     149             :      , mozilla::Move(_notifier)
     150             : #  define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT \
     151             :        mozilla::Move(_notifier)
     152             : #  define MOZ_GUARD_OBJECT_NOTIFIER_INIT \
     153             :      do { _mCheckNotUsedAsTemporary.init(_notifier); } while (0)
     154             : #else
     155             : #  define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
     156             : #  define MOZ_GUARD_OBJECT_NOTIFIER_PARAM
     157             : #  define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM
     158             : #  define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL
     159             : #  define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL
     160             : #  define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT
     161             : #  define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT
     162             : #  define MOZ_GUARD_OBJECT_NOTIFIER_INIT do { } while (0)
     163             : #endif
     164             : 
     165             : #endif /* __cplusplus */
     166             : 
     167             : #endif /* mozilla_GuardObjects_h */

Generated by: LCOV version 1.13