Tue, 06 Jan 2015 21:39:09 +0100
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.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ |
michael@0 | 2 | /* vim: set ts=2 sw=2 et tw=79: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 5 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | /** |
michael@0 | 8 | * A struct for tracking exceptions that need to be thrown to JS. |
michael@0 | 9 | */ |
michael@0 | 10 | |
michael@0 | 11 | #ifndef mozilla_ErrorResult_h |
michael@0 | 12 | #define mozilla_ErrorResult_h |
michael@0 | 13 | |
michael@0 | 14 | #include <stdarg.h> |
michael@0 | 15 | |
michael@0 | 16 | #include "js/Value.h" |
michael@0 | 17 | #include "nscore.h" |
michael@0 | 18 | #include "nsStringGlue.h" |
michael@0 | 19 | #include "mozilla/Assertions.h" |
michael@0 | 20 | |
michael@0 | 21 | namespace mozilla { |
michael@0 | 22 | |
michael@0 | 23 | namespace dom { |
michael@0 | 24 | |
michael@0 | 25 | enum ErrNum { |
michael@0 | 26 | #define MSG_DEF(_name, _argc, _str) \ |
michael@0 | 27 | _name, |
michael@0 | 28 | #include "mozilla/dom/Errors.msg" |
michael@0 | 29 | #undef MSG_DEF |
michael@0 | 30 | Err_Limit |
michael@0 | 31 | }; |
michael@0 | 32 | |
michael@0 | 33 | bool |
michael@0 | 34 | ThrowErrorMessage(JSContext* aCx, const ErrNum aErrorNumber, ...); |
michael@0 | 35 | |
michael@0 | 36 | } // namespace dom |
michael@0 | 37 | |
michael@0 | 38 | class ErrorResult { |
michael@0 | 39 | public: |
michael@0 | 40 | ErrorResult() { |
michael@0 | 41 | mResult = NS_OK; |
michael@0 | 42 | |
michael@0 | 43 | #ifdef DEBUG |
michael@0 | 44 | // ErrorResult is extremely performance-sensitive code, where literally |
michael@0 | 45 | // every machine instruction matters. Initialize mMessage only to suppress |
michael@0 | 46 | // a debug-only warning from gcc 4.6. |
michael@0 | 47 | mMessage = nullptr; |
michael@0 | 48 | mMightHaveUnreportedJSException = false; |
michael@0 | 49 | #endif |
michael@0 | 50 | } |
michael@0 | 51 | |
michael@0 | 52 | #ifdef DEBUG |
michael@0 | 53 | ~ErrorResult() { |
michael@0 | 54 | MOZ_ASSERT_IF(IsTypeError(), !mMessage); |
michael@0 | 55 | MOZ_ASSERT(!mMightHaveUnreportedJSException); |
michael@0 | 56 | } |
michael@0 | 57 | #endif |
michael@0 | 58 | |
michael@0 | 59 | void Throw(nsresult rv) { |
michael@0 | 60 | MOZ_ASSERT(NS_FAILED(rv), "Please don't try throwing success"); |
michael@0 | 61 | MOZ_ASSERT(rv != NS_ERROR_TYPE_ERR, "Use ThrowTypeError()"); |
michael@0 | 62 | MOZ_ASSERT(!IsTypeError(), "Don't overwite TypeError"); |
michael@0 | 63 | MOZ_ASSERT(rv != NS_ERROR_DOM_JS_EXCEPTION, "Use ThrowJSException()"); |
michael@0 | 64 | MOZ_ASSERT(!IsJSException(), "Don't overwrite JS exceptions"); |
michael@0 | 65 | MOZ_ASSERT(rv != NS_ERROR_XPC_NOT_ENOUGH_ARGS, "Use ThrowNotEnoughArgsError()"); |
michael@0 | 66 | MOZ_ASSERT(!IsNotEnoughArgsError(), "Don't overwrite not enough args error"); |
michael@0 | 67 | mResult = rv; |
michael@0 | 68 | } |
michael@0 | 69 | |
michael@0 | 70 | void ThrowTypeError(const dom::ErrNum errorNumber, ...); |
michael@0 | 71 | void ReportTypeError(JSContext* cx); |
michael@0 | 72 | void ClearMessage(); |
michael@0 | 73 | bool IsTypeError() const { return ErrorCode() == NS_ERROR_TYPE_ERR; } |
michael@0 | 74 | |
michael@0 | 75 | // Facilities for throwing a preexisting JS exception value via this |
michael@0 | 76 | // ErrorResult. The contract is that any code which might end up calling |
michael@0 | 77 | // ThrowJSException() must call MightThrowJSException() even if no exception |
michael@0 | 78 | // is being thrown. Code that would call ReportJSException* or |
michael@0 | 79 | // StealJSException as needed must first call WouldReportJSException even if |
michael@0 | 80 | // this ErrorResult has not failed. |
michael@0 | 81 | // |
michael@0 | 82 | // The exn argument to ThrowJSException can be in any compartment. It does |
michael@0 | 83 | // not have to be in the compartment of cx. If someone later uses it, they |
michael@0 | 84 | // will wrap it into whatever compartment they're working in, as needed. |
michael@0 | 85 | void ThrowJSException(JSContext* cx, JS::Handle<JS::Value> exn); |
michael@0 | 86 | void ReportJSException(JSContext* cx); |
michael@0 | 87 | // Used to implement throwing exceptions from the JS implementation of |
michael@0 | 88 | // bindings to callers of the binding. |
michael@0 | 89 | void ReportJSExceptionFromJSImplementation(JSContext* aCx); |
michael@0 | 90 | bool IsJSException() const { return ErrorCode() == NS_ERROR_DOM_JS_EXCEPTION; } |
michael@0 | 91 | |
michael@0 | 92 | void ThrowNotEnoughArgsError() { mResult = NS_ERROR_XPC_NOT_ENOUGH_ARGS; } |
michael@0 | 93 | void ReportNotEnoughArgsError(JSContext* cx, |
michael@0 | 94 | const char* ifaceName, |
michael@0 | 95 | const char* memberName); |
michael@0 | 96 | bool IsNotEnoughArgsError() const { return ErrorCode() == NS_ERROR_XPC_NOT_ENOUGH_ARGS; } |
michael@0 | 97 | |
michael@0 | 98 | // StealJSException steals the JS Exception from the object. This method must |
michael@0 | 99 | // be called only if IsJSException() returns true. This method also resets the |
michael@0 | 100 | // ErrorCode() to NS_OK. |
michael@0 | 101 | void StealJSException(JSContext* cx, JS::MutableHandle<JS::Value> value); |
michael@0 | 102 | |
michael@0 | 103 | void MOZ_ALWAYS_INLINE MightThrowJSException() |
michael@0 | 104 | { |
michael@0 | 105 | #ifdef DEBUG |
michael@0 | 106 | mMightHaveUnreportedJSException = true; |
michael@0 | 107 | #endif |
michael@0 | 108 | } |
michael@0 | 109 | void MOZ_ALWAYS_INLINE WouldReportJSException() |
michael@0 | 110 | { |
michael@0 | 111 | #ifdef DEBUG |
michael@0 | 112 | mMightHaveUnreportedJSException = false; |
michael@0 | 113 | #endif |
michael@0 | 114 | } |
michael@0 | 115 | |
michael@0 | 116 | // In the future, we can add overloads of Throw that take more |
michael@0 | 117 | // interesting things, like strings or DOM exception types or |
michael@0 | 118 | // something if desired. |
michael@0 | 119 | |
michael@0 | 120 | // Backwards-compat to make conversion simpler. We don't call |
michael@0 | 121 | // Throw() here because people can easily pass success codes to |
michael@0 | 122 | // this. |
michael@0 | 123 | void operator=(nsresult rv) { |
michael@0 | 124 | MOZ_ASSERT(rv != NS_ERROR_TYPE_ERR, "Use ThrowTypeError()"); |
michael@0 | 125 | MOZ_ASSERT(!IsTypeError(), "Don't overwite TypeError"); |
michael@0 | 126 | MOZ_ASSERT(rv != NS_ERROR_DOM_JS_EXCEPTION, "Use ThrowJSException()"); |
michael@0 | 127 | MOZ_ASSERT(!IsJSException(), "Don't overwrite JS exceptions"); |
michael@0 | 128 | MOZ_ASSERT(rv != NS_ERROR_XPC_NOT_ENOUGH_ARGS, "Use ThrowNotEnoughArgsError()"); |
michael@0 | 129 | MOZ_ASSERT(!IsNotEnoughArgsError(), "Don't overwrite not enough args error"); |
michael@0 | 130 | mResult = rv; |
michael@0 | 131 | } |
michael@0 | 132 | |
michael@0 | 133 | bool Failed() const { |
michael@0 | 134 | return NS_FAILED(mResult); |
michael@0 | 135 | } |
michael@0 | 136 | |
michael@0 | 137 | nsresult ErrorCode() const { |
michael@0 | 138 | return mResult; |
michael@0 | 139 | } |
michael@0 | 140 | |
michael@0 | 141 | private: |
michael@0 | 142 | nsresult mResult; |
michael@0 | 143 | struct Message; |
michael@0 | 144 | // mMessage is set by ThrowTypeError and cleared (and deallocatd) by |
michael@0 | 145 | // ReportTypeError. |
michael@0 | 146 | // mJSException is set (and rooted) by ThrowJSException and unrooted |
michael@0 | 147 | // by ReportJSException. |
michael@0 | 148 | union { |
michael@0 | 149 | Message* mMessage; // valid when IsTypeError() |
michael@0 | 150 | JS::Value mJSException; // valid when IsJSException() |
michael@0 | 151 | }; |
michael@0 | 152 | |
michael@0 | 153 | #ifdef DEBUG |
michael@0 | 154 | // Used to keep track of codepaths that might throw JS exceptions, |
michael@0 | 155 | // for assertion purposes. |
michael@0 | 156 | bool mMightHaveUnreportedJSException; |
michael@0 | 157 | #endif |
michael@0 | 158 | |
michael@0 | 159 | // Not to be implemented, to make sure people always pass this by |
michael@0 | 160 | // reference, not by value. |
michael@0 | 161 | ErrorResult(const ErrorResult&) MOZ_DELETE; |
michael@0 | 162 | }; |
michael@0 | 163 | |
michael@0 | 164 | /****************************************************************************** |
michael@0 | 165 | ** Macros for checking results |
michael@0 | 166 | ******************************************************************************/ |
michael@0 | 167 | |
michael@0 | 168 | #define ENSURE_SUCCESS(res, ret) \ |
michael@0 | 169 | do { \ |
michael@0 | 170 | if (res.Failed()) { \ |
michael@0 | 171 | nsCString msg; \ |
michael@0 | 172 | msg.AppendPrintf("ENSURE_SUCCESS(%s, %s) failed with " \ |
michael@0 | 173 | "result 0x%X", #res, #ret, res.ErrorCode()); \ |
michael@0 | 174 | NS_WARNING(msg.get()); \ |
michael@0 | 175 | return ret; \ |
michael@0 | 176 | } \ |
michael@0 | 177 | } while(0) |
michael@0 | 178 | |
michael@0 | 179 | #define ENSURE_SUCCESS_VOID(res) \ |
michael@0 | 180 | do { \ |
michael@0 | 181 | if (res.Failed()) { \ |
michael@0 | 182 | nsCString msg; \ |
michael@0 | 183 | msg.AppendPrintf("ENSURE_SUCCESS_VOID(%s) failed with " \ |
michael@0 | 184 | "result 0x%X", #res, res.ErrorCode()); \ |
michael@0 | 185 | NS_WARNING(msg.get()); \ |
michael@0 | 186 | return; \ |
michael@0 | 187 | } \ |
michael@0 | 188 | } while(0) |
michael@0 | 189 | |
michael@0 | 190 | } // namespace mozilla |
michael@0 | 191 | |
michael@0 | 192 | #endif /* mozilla_ErrorResult_h */ |