1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mfbt/GuardObjects.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,152 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* Implementation of macros to ensure correct use of RAII Auto* objects. */ 1.11 + 1.12 +#ifndef mozilla_GuardObjects_h 1.13 +#define mozilla_GuardObjects_h 1.14 + 1.15 +#include "mozilla/Assertions.h" 1.16 +#include "mozilla/NullPtr.h" 1.17 +#include "mozilla/Types.h" 1.18 + 1.19 +#ifdef __cplusplus 1.20 + 1.21 +#ifdef DEBUG 1.22 + 1.23 +namespace mozilla { 1.24 +namespace detail { 1.25 + 1.26 +/* 1.27 + * The following classes are designed to cause assertions to detect 1.28 + * inadvertent use of guard objects as temporaries. In other words, 1.29 + * when we have a guard object whose only purpose is its constructor and 1.30 + * destructor (and is never otherwise referenced), the intended use 1.31 + * might be: 1.32 + * 1.33 + * AutoRestore savePainting(mIsPainting); 1.34 + * 1.35 + * but is is easy to accidentally write: 1.36 + * 1.37 + * AutoRestore(mIsPainting); 1.38 + * 1.39 + * which compiles just fine, but runs the destructor well before the 1.40 + * intended time. 1.41 + * 1.42 + * They work by adding (#ifdef DEBUG) an additional parameter to the 1.43 + * guard object's constructor, with a default value, so that users of 1.44 + * the guard object's API do not need to do anything. The default value 1.45 + * of this parameter is a temporary object. C++ (ISO/IEC 14882:1998), 1.46 + * section 12.2 [class.temporary], clauses 4 and 5 seem to assume a 1.47 + * guarantee that temporaries are destroyed in the reverse of their 1.48 + * construction order, but I actually can't find a statement that that 1.49 + * is true in the general case (beyond the two specific cases mentioned 1.50 + * there). However, it seems to be true. 1.51 + * 1.52 + * These classes are intended to be used only via the macros immediately 1.53 + * below them: 1.54 + * 1.55 + * MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER declares (ifdef DEBUG) a member 1.56 + * variable, and should be put where a declaration of a private 1.57 + * member variable would be placed. 1.58 + * MOZ_GUARD_OBJECT_NOTIFIER_PARAM should be placed at the end of the 1.59 + * parameters to each constructor of the guard object; it declares 1.60 + * (ifdef DEBUG) an additional parameter. (But use the *_ONLY_PARAM 1.61 + * variant for constructors that take no other parameters.) 1.62 + * MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL should likewise be used in 1.63 + * the implementation of such constructors when they are not inline. 1.64 + * MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT should be used in 1.65 + * the implementation of such constructors to pass the parameter to 1.66 + * a base class that also uses these macros 1.67 + * MOZ_GUARD_OBJECT_NOTIFIER_INIT is a statement that belongs in each 1.68 + * constructor. It uses the parameter declared by 1.69 + * MOZ_GUARD_OBJECT_NOTIFIER_PARAM. 1.70 + * 1.71 + * For more details, and examples of using these macros, see 1.72 + * https://developer.mozilla.org/en/Using_RAII_classes_in_Mozilla 1.73 + */ 1.74 +class GuardObjectNotifier 1.75 +{ 1.76 + private: 1.77 + bool* statementDone; 1.78 + 1.79 + public: 1.80 + GuardObjectNotifier() : statementDone(nullptr) { } 1.81 + 1.82 + ~GuardObjectNotifier() { 1.83 + *statementDone = true; 1.84 + } 1.85 + 1.86 + void setStatementDone(bool* statementIsDone) { 1.87 + statementDone = statementIsDone; 1.88 + } 1.89 +}; 1.90 + 1.91 +class GuardObjectNotificationReceiver 1.92 +{ 1.93 + private: 1.94 + bool statementDone; 1.95 + 1.96 + public: 1.97 + GuardObjectNotificationReceiver() : statementDone(false) { } 1.98 + 1.99 + ~GuardObjectNotificationReceiver() { 1.100 + /* 1.101 + * Assert that the guard object was not used as a temporary. (Note that 1.102 + * this assert might also fire if init is not called because the guard 1.103 + * object's implementation is not using the above macros correctly.) 1.104 + */ 1.105 + MOZ_ASSERT(statementDone); 1.106 + } 1.107 + 1.108 + void init(const GuardObjectNotifier& constNotifier) { 1.109 + /* 1.110 + * constNotifier is passed as a const reference so that we can pass a 1.111 + * temporary, but we really intend it as non-const. 1.112 + */ 1.113 + GuardObjectNotifier& notifier = const_cast<GuardObjectNotifier&>(constNotifier); 1.114 + notifier.setStatementDone(&statementDone); 1.115 + } 1.116 +}; 1.117 + 1.118 +} /* namespace detail */ 1.119 +} /* namespace mozilla */ 1.120 + 1.121 +#endif /* DEBUG */ 1.122 + 1.123 +#ifdef DEBUG 1.124 +# define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER \ 1.125 + mozilla::detail::GuardObjectNotificationReceiver _mCheckNotUsedAsTemporary; 1.126 +# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM \ 1.127 + , const mozilla::detail::GuardObjectNotifier& _notifier = \ 1.128 + mozilla::detail::GuardObjectNotifier() 1.129 +# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM \ 1.130 + const mozilla::detail::GuardObjectNotifier& _notifier = \ 1.131 + mozilla::detail::GuardObjectNotifier() 1.132 +# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL \ 1.133 + , const mozilla::detail::GuardObjectNotifier& _notifier 1.134 +# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL \ 1.135 + const mozilla::detail::GuardObjectNotifier& _notifier 1.136 +# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT \ 1.137 + , _notifier 1.138 +# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT \ 1.139 + _notifier 1.140 +# define MOZ_GUARD_OBJECT_NOTIFIER_INIT \ 1.141 + do { _mCheckNotUsedAsTemporary.init(_notifier); } while (0) 1.142 +#else 1.143 +# define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER 1.144 +# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM 1.145 +# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM 1.146 +# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL 1.147 +# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL 1.148 +# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT 1.149 +# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT 1.150 +# define MOZ_GUARD_OBJECT_NOTIFIER_INIT do { } while (0) 1.151 +#endif 1.152 + 1.153 +#endif /* __cplusplus */ 1.154 + 1.155 +#endif /* mozilla_GuardObjects_h */