XPCThrower.cpp (4492B)
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 /* Code for throwing errors into JavaScript. */ 8 9 #include "xpcprivate.h" 10 #include "XPCWrapper.h" 11 #include "js/CharacterEncoding.h" 12 #include "js/Printf.h" 13 #include "mozilla/dom/BindingUtils.h" 14 #include "mozilla/dom/DOMException.h" 15 #include "mozilla/dom/Exceptions.h" 16 #include "nsString.h" 17 18 using namespace mozilla; 19 using namespace mozilla::dom; 20 21 bool XPCThrower::sVerbose = true; 22 23 // static 24 void XPCThrower::Throw(nsresult rv, JSContext* cx) { 25 const char* format; 26 if (JS_IsExceptionPending(cx)) { 27 return; 28 } 29 if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format)) { 30 format = ""; 31 } 32 dom::Throw(cx, rv, nsDependentCString(format)); 33 } 34 35 namespace xpc { 36 37 bool Throw(JSContext* cx, nsresult rv) { 38 XPCThrower::Throw(rv, cx); 39 return false; 40 } 41 42 } // namespace xpc 43 44 /* 45 * If there has already been an exception thrown, see if we're throwing the 46 * same sort of exception, and if we are, don't clobber the old one. ccx 47 * should be the current call context. 48 */ 49 // static 50 bool XPCThrower::CheckForPendingException(nsresult result, JSContext* cx) { 51 RefPtr<Exception> e = XPCJSContext::Get()->GetPendingException(); 52 if (!e) { 53 return false; 54 } 55 XPCJSContext::Get()->SetPendingException(nullptr); 56 57 if (e->GetResult() != result) { 58 return false; 59 } 60 61 ThrowExceptionObject(cx, e); 62 return true; 63 } 64 65 // static 66 void XPCThrower::Throw(nsresult rv, XPCCallContext& ccx) { 67 char* sz; 68 const char* format; 69 70 if (CheckForPendingException(rv, ccx)) { 71 return; 72 } 73 74 if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format)) { 75 format = ""; 76 } 77 78 sz = (char*)format; 79 NS_ENSURE_TRUE_VOID(sz); 80 81 if (sz && sVerbose) { 82 Verbosify(ccx, &sz, false); 83 } 84 85 dom::Throw(ccx, rv, nsDependentCString(sz)); 86 87 if (sz && sz != format) { 88 js_free(sz); 89 } 90 } 91 92 // static 93 void XPCThrower::ThrowBadResult(nsresult rv, nsresult result, 94 XPCCallContext& ccx) { 95 char* sz; 96 const char* format; 97 const char* name; 98 99 /* 100 * If there is a pending exception when the native call returns and 101 * it has the same error result as returned by the native call, then 102 * the native call may be passing through an error from a previous JS 103 * call. So we'll just throw that exception into our JS. Note that 104 * we don't need to worry about NS_ERROR_UNCATCHABLE_EXCEPTION, 105 * because presumably there would be no pending exception for that 106 * nsresult! 107 */ 108 109 if (CheckForPendingException(result, ccx)) { 110 return; 111 } 112 113 // else... 114 115 if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format) || 116 !format) { 117 format = ""; 118 } 119 120 if (nsXPCException::NameAndFormatForNSResult(result, &name, nullptr) && 121 name) { 122 sz = JS_smprintf("%s 0x%x (%s)", format, (unsigned)result, name).release(); 123 } else { 124 sz = JS_smprintf("%s 0x%x", format, (unsigned)result).release(); 125 } 126 NS_ENSURE_TRUE_VOID(sz); 127 128 if (sz && sVerbose) { 129 Verbosify(ccx, &sz, true); 130 } 131 132 dom::Throw(ccx, result, nsDependentCString(sz)); 133 134 if (sz) { 135 js_free(sz); 136 } 137 } 138 139 // static 140 void XPCThrower::ThrowBadParam(nsresult rv, unsigned paramNum, 141 XPCCallContext& ccx) { 142 char* sz; 143 const char* format; 144 145 if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format)) { 146 format = ""; 147 } 148 149 sz = JS_smprintf("%s arg %d", format, paramNum).release(); 150 NS_ENSURE_TRUE_VOID(sz); 151 152 if (sz && sVerbose) { 153 Verbosify(ccx, &sz, true); 154 } 155 156 dom::Throw(ccx, rv, nsDependentCString(sz)); 157 158 if (sz) { 159 js_free(sz); 160 } 161 } 162 163 // static 164 void XPCThrower::Verbosify(XPCCallContext& ccx, char** psz, bool own) { 165 char* sz = nullptr; 166 167 if (ccx.HasInterfaceAndMember()) { 168 XPCNativeInterface* iface = ccx.GetInterface(); 169 jsid id = ccx.GetMember()->GetName(); 170 const char* name; 171 JS::UniqueChars bytes; 172 if (!id.isVoid()) { 173 bytes = JS_EncodeStringToLatin1(ccx, id.toString()); 174 name = bytes ? bytes.get() : ""; 175 } else { 176 name = "Unknown"; 177 } 178 sz = 179 JS_smprintf("%s [%s.%s]", *psz, iface->GetNameString(), name).release(); 180 } 181 182 if (sz) { 183 if (own) { 184 js_free(*psz); 185 } 186 *psz = sz; 187 } 188 }