123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- /* Implementation of macros to ensure correct use of RAII Auto* objects. */
- #ifndef mozilla_GuardObjects_h
- #define mozilla_GuardObjects_h
- #include "mozilla/Assertions.h"
- #include "mozilla/Move.h"
- #include "mozilla/Types.h"
- #ifdef __cplusplus
- #ifdef DEBUG
- /**
- * A custom define is used rather than |mozPoisonValue()| due to cascading
- * build failures relating to how mfbt is linked on different operating
- * systems. See bug 1160253.
- */
- #define MOZ_POISON uintptr_t(-1)
- namespace mozilla {
- namespace detail {
- /*
- * The following classes are designed to cause assertions to detect
- * inadvertent use of guard objects as temporaries. In other words,
- * when we have a guard object whose only purpose is its constructor and
- * destructor (and is never otherwise referenced), the intended use
- * might be:
- *
- * AutoRestore savePainting(mIsPainting);
- *
- * but is is easy to accidentally write:
- *
- * AutoRestore(mIsPainting);
- *
- * which compiles just fine, but runs the destructor well before the
- * intended time.
- *
- * They work by adding (#ifdef DEBUG) an additional parameter to the
- * guard object's constructor, with a default value, so that users of
- * the guard object's API do not need to do anything. The default value
- * of this parameter is a temporary object. C++ (ISO/IEC 14882:1998),
- * section 12.2 [class.temporary], clauses 4 and 5 seem to assume a
- * guarantee that temporaries are destroyed in the reverse of their
- * construction order, but I actually can't find a statement that that
- * is true in the general case (beyond the two specific cases mentioned
- * there). However, it seems to be true.
- *
- * These classes are intended to be used only via the macros immediately
- * below them:
- *
- * MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER declares (ifdef DEBUG) a member
- * variable, and should be put where a declaration of a private
- * member variable would be placed.
- * MOZ_GUARD_OBJECT_NOTIFIER_PARAM should be placed at the end of the
- * parameters to each constructor of the guard object; it declares
- * (ifdef DEBUG) an additional parameter. (But use the *_ONLY_PARAM
- * variant for constructors that take no other parameters.)
- * MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL should likewise be used in
- * the implementation of such constructors when they are not inline.
- * MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT should be used in
- * the implementation of such constructors to pass the parameter to
- * a base class that also uses these macros
- * MOZ_GUARD_OBJECT_NOTIFIER_INIT is a statement that belongs in each
- * constructor. It uses the parameter declared by
- * MOZ_GUARD_OBJECT_NOTIFIER_PARAM.
- *
- * For more details, and examples of using these macros, see
- * https://developer.mozilla.org/en/Using_RAII_classes_in_Mozilla
- */
- class GuardObjectNotifier
- {
- private:
- bool* mStatementDone;
- public:
- GuardObjectNotifier()
- : mStatementDone(reinterpret_cast<bool*>(MOZ_POISON))
- {
- }
- ~GuardObjectNotifier()
- {
- // Assert that the GuardObjectNotifier has been properly initialized by
- // using the |MOZ_GUARD_OBJECT_NOTIFIER_INIT| macro. A poison value is
- // used rather than a null check to appease static analyzers that were
- // (incorrectly) detecting null pointer dereferences.
- MOZ_ASSERT(mStatementDone != reinterpret_cast<bool*>(MOZ_POISON));
- *mStatementDone = true;
- }
- void setStatementDone(bool* aStatementIsDone)
- {
- mStatementDone = aStatementIsDone;
- }
- };
- class GuardObjectNotificationReceiver
- {
- private:
- bool mStatementDone;
- public:
- GuardObjectNotificationReceiver() : mStatementDone(false) { }
- ~GuardObjectNotificationReceiver() {
- /*
- * Assert that the guard object was not used as a temporary. (Note that
- * this assert might also fire if init is not called because the guard
- * object's implementation is not using the above macros correctly.)
- */
- MOZ_ASSERT(mStatementDone);
- }
- void init(GuardObjectNotifier& aNotifier)
- {
- aNotifier.setStatementDone(&mStatementDone);
- }
- };
- } /* namespace detail */
- } /* namespace mozilla */
- #undef MOZ_POISON
- #endif /* DEBUG */
- #ifdef DEBUG
- # define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER \
- mozilla::detail::GuardObjectNotificationReceiver _mCheckNotUsedAsTemporary;
- # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM \
- , mozilla::detail::GuardObjectNotifier&& _notifier = \
- mozilla::detail::GuardObjectNotifier()
- # define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM \
- mozilla::detail::GuardObjectNotifier&& _notifier = \
- mozilla::detail::GuardObjectNotifier()
- # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL \
- , mozilla::detail::GuardObjectNotifier&& _notifier
- # define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL \
- mozilla::detail::GuardObjectNotifier&& _notifier
- # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT \
- , mozilla::Move(_notifier)
- # define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT \
- mozilla::Move(_notifier)
- # define MOZ_GUARD_OBJECT_NOTIFIER_INIT \
- do { _mCheckNotUsedAsTemporary.init(_notifier); } while (0)
- #else
- # define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
- # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM
- # define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM
- # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL
- # define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL
- # define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT
- # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT
- # define MOZ_GUARD_OBJECT_NOTIFIER_INIT do { } while (0)
- #endif
- #endif /* __cplusplus */
- #endif /* mozilla_GuardObjects_h */
|