LCOV - code coverage report
Current view: top level - dom/bindings - ErrorResult.h (source / functions) Hit Total Coverage
Test: output.info Lines: 83 148 56.1 %
Date: 2017-07-14 16:53:18 Functions: 47 753 6.2 %
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 file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /**
       8             :  * A set of structs for tracking exceptions that need to be thrown to JS:
       9             :  * ErrorResult and IgnoredErrorResult.
      10             :  *
      11             :  * Conceptually, these structs represent either success or an exception in the
      12             :  * process of being thrown.  This means that a failing ErrorResult _must_ be
      13             :  * handled in one of the following ways before coming off the stack:
      14             :  *
      15             :  * 1) Suppressed via SuppressException().
      16             :  * 2) Converted to a pure nsresult return value via StealNSResult().
      17             :  * 3) Converted to an actual pending exception on a JSContext via
      18             :  *    MaybeSetPendingException.
      19             :  * 4) Converted to an exception JS::Value (probably to then reject a Promise
      20             :  *    with) via dom::ToJSValue.
      21             :  *
      22             :  * An IgnoredErrorResult will automatically do the first of those four things.
      23             :  */
      24             : 
      25             : #ifndef mozilla_ErrorResult_h
      26             : #define mozilla_ErrorResult_h
      27             : 
      28             : #include <stdarg.h>
      29             : 
      30             : #include "js/GCAnnotations.h"
      31             : #include "js/Value.h"
      32             : #include "nscore.h"
      33             : #include "nsStringGlue.h"
      34             : #include "mozilla/Assertions.h"
      35             : #include "mozilla/Move.h"
      36             : #include "nsTArray.h"
      37             : #include "nsISupportsImpl.h"
      38             : 
      39             : namespace IPC {
      40             : class Message;
      41             : template <typename> struct ParamTraits;
      42             : } // namespace IPC
      43             : class PickleIterator;
      44             : 
      45             : namespace mozilla {
      46             : 
      47             : namespace dom {
      48             : 
      49             : enum ErrNum {
      50             : #define MSG_DEF(_name, _argc, _exn, _str) \
      51             :   _name,
      52             : #include "mozilla/dom/Errors.msg"
      53             : #undef MSG_DEF
      54             :   Err_Limit
      55             : };
      56             : 
      57             : // Debug-only compile-time table of the number of arguments of each error, for use in static_assert.
      58             : #if defined(DEBUG) && (defined(__clang__) || defined(__GNUC__))
      59             : uint16_t constexpr ErrorFormatNumArgs[] = {
      60             : #define MSG_DEF(_name, _argc, _exn, _str) \
      61             :   _argc,
      62             : #include "mozilla/dom/Errors.msg"
      63             : #undef MSG_DEF
      64             : };
      65             : #endif
      66             : 
      67             : uint16_t
      68             : GetErrorArgCount(const ErrNum aErrorNumber);
      69             : 
      70             : namespace binding_detail {
      71             : void ThrowErrorMessage(JSContext* aCx, const unsigned aErrorNumber, ...);
      72             : } // namespace binding_detail
      73             : 
      74             : template<typename... Ts>
      75             : inline bool
      76           0 : ThrowErrorMessage(JSContext* aCx, const ErrNum aErrorNumber, Ts&&... aArgs)
      77             : {
      78           0 :   binding_detail::ThrowErrorMessage(aCx, static_cast<const unsigned>(aErrorNumber),
      79           0 :                                     mozilla::Forward<Ts>(aArgs)...);
      80           0 :   return false;
      81             : }
      82             : 
      83             : struct StringArrayAppender
      84             : {
      85           0 :   static void Append(nsTArray<nsString>& aArgs, uint16_t aCount)
      86             :   {
      87           0 :     MOZ_RELEASE_ASSERT(aCount == 0, "Must give at least as many string arguments as are required by the ErrNum.");
      88           0 :   }
      89             : 
      90             :   template<typename... Ts>
      91           0 :   static void Append(nsTArray<nsString>& aArgs, uint16_t aCount, const nsAString& aFirst, Ts&&... aOtherArgs)
      92             :   {
      93           0 :     if (aCount == 0) {
      94           0 :       MOZ_ASSERT(false, "There should not be more string arguments provided than are required by the ErrNum.");
      95             :       return;
      96             :     }
      97           0 :     aArgs.AppendElement(aFirst);
      98           0 :     Append(aArgs, aCount - 1, Forward<Ts>(aOtherArgs)...);
      99           0 :   }
     100             : };
     101             : 
     102             : } // namespace dom
     103             : 
     104             : class ErrorResult;
     105             : class OOMReporter;
     106             : 
     107             : namespace binding_danger {
     108             : 
     109             : /**
     110             :  * Templated implementation class for various ErrorResult-like things.  The
     111             :  * instantiations differ only in terms of their cleanup policies (used in the
     112             :  * destructor), which they can specify via the template argument.  Note that
     113             :  * this means it's safe to reinterpret_cast between the instantiations unless
     114             :  * you plan to invoke the destructor through such a cast pointer.
     115             :  *
     116             :  * A cleanup policy consists of two booleans: whether to assert that we've been
     117             :  * reported or suppressed, and whether to then go ahead and suppress the
     118             :  * exception.
     119             :  */
     120             : template<typename CleanupPolicy>
     121             : class TErrorResult {
     122             : public:
     123        2359 :   TErrorResult()
     124             :     : mResult(NS_OK)
     125             : #ifdef DEBUG
     126             :     , mMightHaveUnreportedJSException(false)
     127        2359 :     , mUnionState(HasNothing)
     128             : #endif
     129             :   {
     130        2359 :   }
     131             : 
     132        2355 :   ~TErrorResult() {
     133        2355 :     AssertInOwningThread();
     134             : 
     135             :     if (CleanupPolicy::assertHandled) {
     136             :       // Consumers should have called one of MaybeSetPendingException
     137             :       // (possibly via ToJSValue), StealNSResult, and SuppressException
     138        1918 :       AssertReportedOrSuppressed();
     139             :     }
     140             : 
     141             :     if (CleanupPolicy::suppress) {
     142        1250 :       SuppressException();
     143             :     }
     144             : 
     145             :     // And now assert that we're in a good final state.
     146        2355 :     AssertReportedOrSuppressed();
     147        2355 :   }
     148             : 
     149           0 :   TErrorResult(TErrorResult&& aRHS)
     150             :     // Initialize mResult and whatever else we need to default-initialize, so
     151             :     // the ClearUnionData call in our operator= will do the right thing
     152             :     // (nothing).
     153           0 :     : TErrorResult()
     154             :   {
     155           0 :     *this = Move(aRHS);
     156           0 :   }
     157             :   TErrorResult& operator=(TErrorResult&& aRHS);
     158             : 
     159           0 :   explicit TErrorResult(nsresult aRv)
     160           0 :     : TErrorResult()
     161             :   {
     162           0 :     AssignErrorCode(aRv);
     163           0 :   }
     164             : 
     165             :   operator ErrorResult&();
     166             :   operator OOMReporter&();
     167             : 
     168           0 :   void MOZ_MUST_RETURN_FROM_CALLER Throw(nsresult rv) {
     169           0 :     MOZ_ASSERT(NS_FAILED(rv), "Please don't try throwing success");
     170           0 :     AssignErrorCode(rv);
     171           0 :   }
     172             : 
     173             :   // This method acts identically to the `Throw` method, however, it does not
     174             :   // have the MOZ_MUST_RETURN_FROM_CALLER static analysis annotation. It is
     175             :   // intended to be used in situations when additional work needs to be
     176             :   // performed in the calling function after the Throw method is called.
     177             :   //
     178             :   // In general you should prefer using `Throw`, and returning after an error,
     179             :   // for example:
     180             :   //
     181             :   //   if (condition) {
     182             :   //     aRv.Throw(NS_ERROR_FAILURE);
     183             :   //     return;
     184             :   //   }
     185             :   //
     186             :   // or
     187             :   //
     188             :   //   if (condition) {
     189             :   //     aRv.Throw(NS_ERROR_FAILURE);
     190             :   //   }
     191             :   //   return;
     192             :   //
     193             :   // However, if you need to do some other work after throwing, such as:
     194             :   //
     195             :   //   if (condition) {
     196             :   //     aRv.ThrowWithCustomCleanup(NS_ERROR_FAILURE);
     197             :   //   }
     198             :   //   // Do some important clean-up work which couldn't happen earlier.
     199             :   //   // We want to do this clean-up work in both the success and failure cases.
     200             :   //   CleanUpImportantState();
     201             :   //   return;
     202             :   //
     203             :   // Then you'll need to use ThrowWithCustomCleanup to get around the static
     204             :   // analysis, which would complain that you are doing work after the call to
     205             :   // `Throw()`.
     206           0 :   void ThrowWithCustomCleanup(nsresult rv) {
     207           0 :     Throw(rv);
     208           0 :   }
     209             : 
     210             :   // Duplicate our current state on the given TErrorResult object.  Any
     211             :   // existing errors or messages on the target will be suppressed before
     212             :   // cloning.  Our own error state remains unchanged.
     213             :   void CloneTo(TErrorResult& aRv) const;
     214             : 
     215             :   // Use SuppressException when you want to suppress any exception that might be
     216             :   // on the TErrorResult.  After this call, the TErrorResult will be back a "no
     217             :   // exception thrown" state.
     218             :   void SuppressException();
     219             : 
     220             :   // Use StealNSResult() when you want to safely convert the TErrorResult to
     221             :   // an nsresult that you will then return to a caller.  This will
     222             :   // SuppressException(), since there will no longer be a way to report it.
     223         279 :   nsresult StealNSResult() {
     224         279 :     nsresult rv = ErrorCode();
     225         279 :     SuppressException();
     226             :     // Don't propagate out our internal error codes that have special meaning.
     227         279 :     if (rv == NS_ERROR_INTERNAL_ERRORRESULT_TYPEERROR ||
     228         279 :         rv == NS_ERROR_INTERNAL_ERRORRESULT_RANGEERROR ||
     229         279 :         rv == NS_ERROR_INTERNAL_ERRORRESULT_JS_EXCEPTION ||
     230             :         rv == NS_ERROR_INTERNAL_ERRORRESULT_DOMEXCEPTION) {
     231             :       // What to pick here?
     232           0 :       return NS_ERROR_DOM_INVALID_STATE_ERR;
     233             :     }
     234             : 
     235         279 :     return rv;
     236             :   }
     237             : 
     238             :   // Use MaybeSetPendingException to convert a TErrorResult to a pending
     239             :   // exception on the given JSContext.  This is the normal "throw an exception"
     240             :   // codepath.
     241             :   //
     242             :   // The return value is false if the TErrorResult represents success, true
     243             :   // otherwise.  This does mean that in JSAPI method implementations you can't
     244             :   // just use this as |return rv.MaybeSetPendingException(cx)| (though you could
     245             :   // |return !rv.MaybeSetPendingException(cx)|), but in practice pretty much any
     246             :   // consumer would want to do some more work on the success codepath.  So
     247             :   // instead the way you use this is:
     248             :   //
     249             :   //   if (rv.MaybeSetPendingException(cx)) {
     250             :   //     bail out here
     251             :   //   }
     252             :   //   go on to do something useful
     253             :   //
     254             :   // The success path is inline, since it should be the common case and we don't
     255             :   // want to pay the price of a function call in some of the consumers of this
     256             :   // method in the common case.
     257             :   //
     258             :   // Note that a true return value does NOT mean there is now a pending
     259             :   // exception on aCx, due to uncatchable exceptions.  It should still be
     260             :   // considered equivalent to a JSAPI failure in terms of what callers should do
     261             :   // after true is returned.
     262             :   //
     263             :   // After this call, the TErrorResult will no longer return true from Failed(),
     264             :   // since the exception will have moved to the JSContext.
     265             :   MOZ_MUST_USE
     266        1106 :   bool MaybeSetPendingException(JSContext* cx)
     267             :   {
     268        1106 :     WouldReportJSException();
     269        1106 :     if (!Failed()) {
     270        1106 :       return false;
     271             :     }
     272             : 
     273           0 :     SetPendingException(cx);
     274           0 :     return true;
     275             :   }
     276             : 
     277             :   // Use StealExceptionFromJSContext to convert a pending exception on a
     278             :   // JSContext to a TErrorResult.  This function must be called only when a
     279             :   // JSAPI operation failed.  It assumes that lack of pending exception on the
     280             :   // JSContext means an uncatchable exception was thrown.
     281             :   //
     282             :   // Codepaths that might call this method must call MightThrowJSException even
     283             :   // if the relevant JSAPI calls do not fail.
     284             :   //
     285             :   // When this function returns, JS_IsExceptionPending(cx) will definitely be
     286             :   // false.
     287             :   void StealExceptionFromJSContext(JSContext* cx);
     288             : 
     289             :   template<dom::ErrNum errorNumber, typename... Ts>
     290           0 :   void ThrowTypeError(Ts&&... messageArgs)
     291             :   {
     292           0 :     ThrowErrorWithMessage<errorNumber>(NS_ERROR_INTERNAL_ERRORRESULT_TYPEERROR,
     293             :                                        Forward<Ts>(messageArgs)...);
     294           0 :   }
     295             : 
     296             :   template<dom::ErrNum errorNumber, typename... Ts>
     297           0 :   void ThrowRangeError(Ts&&... messageArgs)
     298             :   {
     299           0 :     ThrowErrorWithMessage<errorNumber>(NS_ERROR_INTERNAL_ERRORRESULT_RANGEERROR,
     300             :                                        Forward<Ts>(messageArgs)...);
     301           0 :   }
     302             : 
     303        2795 :   bool IsErrorWithMessage() const
     304             :   {
     305        5590 :     return ErrorCode() == NS_ERROR_INTERNAL_ERRORRESULT_TYPEERROR ||
     306        5590 :            ErrorCode() == NS_ERROR_INTERNAL_ERRORRESULT_RANGEERROR;
     307             :   }
     308             : 
     309             :   // Facilities for throwing a preexisting JS exception value via this
     310             :   // TErrorResult.  The contract is that any code which might end up calling
     311             :   // ThrowJSException() or StealExceptionFromJSContext() must call
     312             :   // MightThrowJSException() even if no exception is being thrown.  Code that
     313             :   // conditionally calls ToJSValue on this TErrorResult only if Failed() must
     314             :   // first call WouldReportJSException even if this TErrorResult has not failed.
     315             :   //
     316             :   // The exn argument to ThrowJSException can be in any compartment.  It does
     317             :   // not have to be in the compartment of cx.  If someone later uses it, they
     318             :   // will wrap it into whatever compartment they're working in, as needed.
     319             :   void ThrowJSException(JSContext* cx, JS::Handle<JS::Value> exn);
     320        2795 :   bool IsJSException() const
     321             :   {
     322        2795 :     return ErrorCode() == NS_ERROR_INTERNAL_ERRORRESULT_JS_EXCEPTION;
     323             :   }
     324             : 
     325             :   // Facilities for throwing a DOMException.  If an empty message string is
     326             :   // passed to ThrowDOMException, the default message string for the given
     327             :   // nsresult will be used.  The passed-in string must be UTF-8.  The nsresult
     328             :   // passed in must be one we create DOMExceptions for; otherwise you may get an
     329             :   // XPConnect Exception.
     330             :   void ThrowDOMException(nsresult rv, const nsACString& message = EmptyCString());
     331        2795 :   bool IsDOMException() const
     332             :   {
     333        2795 :     return ErrorCode() == NS_ERROR_INTERNAL_ERRORRESULT_DOMEXCEPTION;
     334             :   }
     335             : 
     336             :   // Flag on the TErrorResult that whatever needs throwing has been
     337             :   // thrown on the JSContext already and we should not mess with it.
     338             :   // If nothing was thrown, this becomes an uncatchable exception.
     339             :   void NoteJSContextException(JSContext* aCx);
     340             : 
     341             :   // Check whether the TErrorResult says to just throw whatever is on
     342             :   // the JSContext already.
     343           0 :   bool IsJSContextException() {
     344           0 :     return ErrorCode() == NS_ERROR_INTERNAL_ERRORRESULT_EXCEPTION_ON_JSCONTEXT;
     345             :   }
     346             : 
     347             :   // Support for uncatchable exceptions.
     348           0 :   void MOZ_MUST_RETURN_FROM_CALLER ThrowUncatchableException() {
     349           0 :     Throw(NS_ERROR_UNCATCHABLE_EXCEPTION);
     350           0 :   }
     351           7 :   bool IsUncatchableException() const {
     352           7 :     return ErrorCode() == NS_ERROR_UNCATCHABLE_EXCEPTION;
     353             :   }
     354             : 
     355           8 :   void MOZ_ALWAYS_INLINE MightThrowJSException()
     356             :   {
     357             : #ifdef DEBUG
     358           8 :     mMightHaveUnreportedJSException = true;
     359             : #endif
     360           8 :   }
     361        2723 :   void MOZ_ALWAYS_INLINE WouldReportJSException()
     362             :   {
     363             : #ifdef DEBUG
     364        2723 :     mMightHaveUnreportedJSException = false;
     365             : #endif
     366        2723 :   }
     367             : 
     368             :   // In the future, we can add overloads of Throw that take more
     369             :   // interesting things, like strings or DOM exception types or
     370             :   // something if desired.
     371             : 
     372             :   // Backwards-compat to make conversion simpler.  We don't call
     373             :   // Throw() here because people can easily pass success codes to
     374             :   // this.
     375        1179 :   void operator=(nsresult rv) {
     376        1179 :     AssignErrorCode(rv);
     377        1179 :   }
     378             : 
     379        7160 :   bool Failed() const {
     380        7160 :     return NS_FAILED(mResult);
     381             :   }
     382             : 
     383           0 :   bool ErrorCodeIs(nsresult rv) const {
     384           0 :     return mResult == rv;
     385             :   }
     386             : 
     387             :   // For use in logging ONLY.
     388           0 :   uint32_t ErrorCodeAsInt() const {
     389           0 :     return static_cast<uint32_t>(ErrorCode());
     390             :   }
     391             : 
     392             : protected:
     393       11466 :   nsresult ErrorCode() const {
     394       11466 :     return mResult;
     395             :   }
     396             : 
     397             : private:
     398             : #ifdef DEBUG
     399             :   enum UnionState {
     400             :     HasMessage,
     401             :     HasDOMExceptionInfo,
     402             :     HasJSException,
     403             :     HasNothing
     404             :   };
     405             : #endif // DEBUG
     406             : 
     407             :   friend struct IPC::ParamTraits<TErrorResult>;
     408             :   friend struct IPC::ParamTraits<ErrorResult>;
     409             :   void SerializeMessage(IPC::Message* aMsg) const;
     410             :   bool DeserializeMessage(const IPC::Message* aMsg, PickleIterator* aIter);
     411             : 
     412             :   void SerializeDOMExceptionInfo(IPC::Message* aMsg) const;
     413             :   bool DeserializeDOMExceptionInfo(const IPC::Message* aMsg, PickleIterator* aIter);
     414             : 
     415             :   // Helper method that creates a new Message for this TErrorResult,
     416             :   // and returns the arguments array from that Message.
     417             :   nsTArray<nsString>& CreateErrorMessageHelper(const dom::ErrNum errorNumber, nsresult errorType);
     418             : 
     419             :   template<dom::ErrNum errorNumber, typename... Ts>
     420           0 :   void ThrowErrorWithMessage(nsresult errorType, Ts&&... messageArgs)
     421             :   {
     422             : #if defined(DEBUG) && (defined(__clang__) || defined(__GNUC__))
     423             :     static_assert(dom::ErrorFormatNumArgs[errorNumber] == sizeof...(messageArgs),
     424             :                   "Pass in the right number of arguments");
     425             : #endif
     426             : 
     427           0 :     ClearUnionData();
     428             : 
     429           0 :     nsTArray<nsString>& messageArgsArray = CreateErrorMessageHelper(errorNumber, errorType);
     430           0 :     uint16_t argCount = dom::GetErrorArgCount(errorNumber);
     431           0 :     dom::StringArrayAppender::Append(messageArgsArray, argCount,
     432           0 :                                      Forward<Ts>(messageArgs)...);
     433             : #ifdef DEBUG
     434           0 :     mUnionState = HasMessage;
     435             : #endif // DEBUG
     436           0 :   }
     437             : 
     438        5587 :   MOZ_ALWAYS_INLINE void AssertInOwningThread() const {
     439             : #ifdef DEBUG
     440        5587 :     NS_ASSERT_OWNINGTHREAD(TErrorResult);
     441             : #endif
     442        5587 :   }
     443             : 
     444        1179 :   void AssignErrorCode(nsresult aRv) {
     445        1179 :     MOZ_ASSERT(aRv != NS_ERROR_INTERNAL_ERRORRESULT_TYPEERROR,
     446             :                "Use ThrowTypeError()");
     447        1179 :     MOZ_ASSERT(aRv != NS_ERROR_INTERNAL_ERRORRESULT_RANGEERROR,
     448             :                "Use ThrowRangeError()");
     449        1179 :     MOZ_ASSERT(!IsErrorWithMessage(), "Don't overwrite errors with message");
     450        1179 :     MOZ_ASSERT(aRv != NS_ERROR_INTERNAL_ERRORRESULT_JS_EXCEPTION,
     451             :                "Use ThrowJSException()");
     452        1179 :     MOZ_ASSERT(!IsJSException(), "Don't overwrite JS exceptions");
     453        1179 :     MOZ_ASSERT(aRv != NS_ERROR_INTERNAL_ERRORRESULT_DOMEXCEPTION,
     454             :                "Use ThrowDOMException()");
     455        1179 :     MOZ_ASSERT(!IsDOMException(), "Don't overwrite DOM exceptions");
     456        1179 :     MOZ_ASSERT(aRv != NS_ERROR_XPC_NOT_ENOUGH_ARGS, "May need to bring back ThrowNotEnoughArgsError");
     457        1179 :     MOZ_ASSERT(aRv != NS_ERROR_INTERNAL_ERRORRESULT_EXCEPTION_ON_JSCONTEXT,
     458             :                "Use NoteJSContextException");
     459        1179 :     mResult = aRv;
     460        1179 :   }
     461             : 
     462             :   void ClearMessage();
     463             :   void ClearDOMExceptionInfo();
     464             : 
     465             :   // ClearUnionData will try to clear the data in our
     466             :   // mMessage/mJSException/mDOMExceptionInfo union.  After this the union may be
     467             :   // in an uninitialized state (e.g. mMessage or mDOMExceptionInfo may be
     468             :   // pointing to deleted memory) and the caller must either reinitialize it or
     469             :   // change mResult to something that will not involve us touching the union
     470             :   // anymore.
     471             :   void ClearUnionData();
     472             : 
     473             :   // Implementation of MaybeSetPendingException for the case when we're a
     474             :   // failure result.
     475             :   void SetPendingException(JSContext* cx);
     476             : 
     477             :   // Methods for setting various specific kinds of pending exceptions.
     478             :   void SetPendingExceptionWithMessage(JSContext* cx);
     479             :   void SetPendingJSException(JSContext* cx);
     480             :   void SetPendingDOMException(JSContext* cx);
     481             :   void SetPendingGenericErrorException(JSContext* cx);
     482             : 
     483        4273 :   MOZ_ALWAYS_INLINE void AssertReportedOrSuppressed()
     484             :   {
     485        4273 :     MOZ_ASSERT(!Failed());
     486        4273 :     MOZ_ASSERT(!mMightHaveUnreportedJSException);
     487        4273 :     MOZ_ASSERT(mUnionState == HasNothing);
     488        4273 :   }
     489             : 
     490             :   // Special values of mResult:
     491             :   // NS_ERROR_INTERNAL_ERRORRESULT_TYPEERROR -- ThrowTypeError() called on us.
     492             :   // NS_ERROR_INTERNAL_ERRORRESULT_RANGEERROR -- ThrowRangeError() called on us.
     493             :   // NS_ERROR_INTERNAL_ERRORRESULT_JS_EXCEPTION -- ThrowJSException() called
     494             :   //                                               on us.
     495             :   // NS_ERROR_UNCATCHABLE_EXCEPTION -- ThrowUncatchableException called on us.
     496             :   // NS_ERROR_INTERNAL_ERRORRESULT_DOMEXCEPTION -- ThrowDOMException() called
     497             :   //                                               on us.
     498             :   nsresult mResult;
     499             : 
     500             :   struct Message;
     501             :   struct DOMExceptionInfo;
     502             :   // mMessage is set by ThrowErrorWithMessage and reported (and deallocated) by
     503             :   // SetPendingExceptionWithMessage.
     504             :   // mJSException is set (and rooted) by ThrowJSException and reported
     505             :   // (and unrooted) by SetPendingJSException.
     506             :   // mDOMExceptionInfo is set by ThrowDOMException and reported
     507             :   // (and deallocated) by SetPendingDOMException.
     508             :   union {
     509             :     Message* mMessage; // valid when IsErrorWithMessage()
     510             :     JS::Value mJSException; // valid when IsJSException()
     511             :     DOMExceptionInfo* mDOMExceptionInfo; // valid when IsDOMException()
     512             :   };
     513             : 
     514             : #ifdef DEBUG
     515             :   // Used to keep track of codepaths that might throw JS exceptions,
     516             :   // for assertion purposes.
     517             :   bool mMightHaveUnreportedJSException;
     518             : 
     519             :   // Used to keep track of what's stored in our union right now.  Note
     520             :   // that this may be set to HasNothing even if our mResult suggests
     521             :   // we should have something, if we have already cleaned up the
     522             :   // something.
     523             :   UnionState mUnionState;
     524             : 
     525             :   // The thread that created this TErrorResult
     526             :   NS_DECL_OWNINGTHREAD;
     527             : #endif
     528             : 
     529             :   // Not to be implemented, to make sure people always pass this by
     530             :   // reference, not by value.
     531             :   TErrorResult(const TErrorResult&) = delete;
     532             :   void operator=(const TErrorResult&) = delete;
     533             : };
     534             : 
     535             : struct JustAssertCleanupPolicy {
     536             :   static const bool assertHandled = true;
     537             :   static const bool suppress = false;
     538             : };
     539             : 
     540             : struct AssertAndSuppressCleanupPolicy {
     541             :   static const bool assertHandled = true;
     542             :   static const bool suppress = true;
     543             : };
     544             : 
     545             : struct JustSuppressCleanupPolicy {
     546             :   static const bool assertHandled = false;
     547             :   static const bool suppress = true;
     548             : };
     549             : 
     550             : } // namespace binding_danger
     551             : 
     552             : // A class people should normally use on the stack when they plan to actually
     553             : // do something with the exception.
     554         813 : class ErrorResult :
     555             :     public binding_danger::TErrorResult<binding_danger::AssertAndSuppressCleanupPolicy>
     556             : {
     557             :   typedef binding_danger::TErrorResult<binding_danger::AssertAndSuppressCleanupPolicy> BaseErrorResult;
     558             : 
     559             : public:
     560         814 :   ErrorResult()
     561         814 :     : BaseErrorResult()
     562         814 :   {}
     563             : 
     564             :   ErrorResult(ErrorResult&& aRHS)
     565             :     : BaseErrorResult(Move(aRHS))
     566             :   {}
     567             : 
     568           0 :   explicit ErrorResult(nsresult aRv)
     569           0 :     : BaseErrorResult(aRv)
     570           0 :   {}
     571             : 
     572        1179 :   void operator=(nsresult rv)
     573             :   {
     574        1179 :     BaseErrorResult::operator=(rv);
     575        1179 :   }
     576             : 
     577           0 :   ErrorResult& operator=(ErrorResult&& aRHS)
     578             :   {
     579           0 :     BaseErrorResult::operator=(Move(aRHS));
     580           0 :     return *this;
     581             :   }
     582             : 
     583             : private:
     584             :   // Not to be implemented, to make sure people always pass this by
     585             :   // reference, not by value.
     586             :   ErrorResult(const ErrorResult&) = delete;
     587             :   void operator=(const ErrorResult&) = delete;
     588             : };
     589             : 
     590             : template<typename CleanupPolicy>
     591        1541 : binding_danger::TErrorResult<CleanupPolicy>::operator ErrorResult&()
     592             : {
     593             :   return *static_cast<ErrorResult*>(
     594        1541 :      reinterpret_cast<TErrorResult<AssertAndSuppressCleanupPolicy>*>(this));
     595             : }
     596             : 
     597             : // A class for use when an ErrorResult should just automatically be ignored.
     598             : // This doesn't inherit from ErrorResult so we don't make two separate calls to
     599             : // SuppressException.
     600         874 : class IgnoredErrorResult :
     601             :     public binding_danger::TErrorResult<binding_danger::JustSuppressCleanupPolicy>
     602             : {
     603             : };
     604             : 
     605             : namespace dom {
     606             : namespace binding_detail {
     607        2213 : class FastErrorResult :
     608             :     public mozilla::binding_danger::TErrorResult<
     609             :       mozilla::binding_danger::JustAssertCleanupPolicy>
     610             : {
     611             : };
     612             : } // namespace binding_detail
     613             : } // namespace dom
     614             : 
     615             : // This part is a bit annoying.  We want an OOMReporter class that has the
     616             : // following properties:
     617             : //
     618             : // 1) Can be cast to from any ErrorResult-like type.
     619             : // 2) Has a fast destructor (because we want to use it from bindings).
     620             : // 3) Won't be randomly instantiated by non-binding code (because the fast
     621             : //    destructor is not so safe.
     622             : // 4) Doesn't look ugly on the callee side (e.g. isn't in the binding_detail or
     623             : //    binding_danger namespace).
     624             : //
     625             : // We do this by having two classes: The class callees should use, which has the
     626             : // things we want and a private constructor, and a friend subclass in the
     627             : // binding_danger namespace that can be used to construct it.
     628             : namespace binding_danger {
     629             : class OOMReporterInstantiator;
     630             : } // namespace binding_danger
     631             : 
     632           4 : class OOMReporter : private dom::binding_detail::FastErrorResult
     633             : {
     634             : public:
     635           0 :   void ReportOOM()
     636             :   {
     637           0 :     Throw(NS_ERROR_OUT_OF_MEMORY);
     638           0 :   }
     639             : 
     640             : private:
     641             :   // OOMReporterInstantiator is a friend so it can call our constructor and
     642             :   // MaybeSetPendingException.
     643             :   friend class binding_danger::OOMReporterInstantiator;
     644             : 
     645             :   // TErrorResult is a friend so its |operator OOMReporter&()| can work.
     646             :   template<typename CleanupPolicy>
     647             :   friend class binding_danger::TErrorResult;
     648             : 
     649           4 :   OOMReporter()
     650           4 :     : dom::binding_detail::FastErrorResult()
     651             :   {
     652           4 :   }
     653             : };
     654             : 
     655             : namespace binding_danger {
     656           4 : class OOMReporterInstantiator : public OOMReporter
     657             : {
     658             : public:
     659           4 :   OOMReporterInstantiator()
     660           4 :     : OOMReporter()
     661             :   {
     662           4 :   }
     663             : 
     664             :   // We want to be able to call MaybeSetPendingException from codegen.  The one
     665             :   // on OOMReporter is not callable directly, because it comes from a private
     666             :   // superclass.  But we're a friend, so _we_ can call it.
     667           4 :   bool MaybeSetPendingException(JSContext* cx)
     668             :   {
     669           4 :     return OOMReporter::MaybeSetPendingException(cx);
     670             :   }
     671             : };
     672             : } // namespace binding_danger
     673             : 
     674             : template<typename CleanupPolicy>
     675           0 : binding_danger::TErrorResult<CleanupPolicy>::operator OOMReporter&()
     676             : {
     677             :   return *static_cast<OOMReporter*>(
     678           0 :      reinterpret_cast<TErrorResult<JustAssertCleanupPolicy>*>(this));
     679             : }
     680             : 
     681             : /******************************************************************************
     682             :  ** Macros for checking results
     683             :  ******************************************************************************/
     684             : 
     685             : #define ENSURE_SUCCESS(res, ret)                                          \
     686             :   do {                                                                    \
     687             :     if (res.Failed()) {                                                   \
     688             :       nsCString msg;                                                      \
     689             :       msg.AppendPrintf("ENSURE_SUCCESS(%s, %s) failed with "              \
     690             :                        "result 0x%X", #res, #ret, res.ErrorCodeAsInt());  \
     691             :       NS_WARNING(msg.get());                                              \
     692             :       return ret;                                                         \
     693             :     }                                                                     \
     694             :   } while(0)
     695             : 
     696             : #define ENSURE_SUCCESS_VOID(res)                                          \
     697             :   do {                                                                    \
     698             :     if (res.Failed()) {                                                   \
     699             :       nsCString msg;                                                      \
     700             :       msg.AppendPrintf("ENSURE_SUCCESS_VOID(%s) failed with "             \
     701             :                        "result 0x%X", #res, res.ErrorCodeAsInt());        \
     702             :       NS_WARNING(msg.get());                                              \
     703             :       return;                                                             \
     704             :     }                                                                     \
     705             :   } while(0)
     706             : 
     707             : } // namespace mozilla
     708             : 
     709             : #endif /* mozilla_ErrorResult_h */

Generated by: LCOV version 1.13