1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/xpconnect/src/XPCThrower.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,173 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim: set ts=8 sts=4 et sw=4 tw=99: */ 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 +/* Code for throwing errors into JavaScript. */ 1.11 + 1.12 +#include "xpcprivate.h" 1.13 +#include "XPCWrapper.h" 1.14 +#include "jsprf.h" 1.15 +#include "mozilla/dom/BindingUtils.h" 1.16 +#include "mozilla/dom/Exceptions.h" 1.17 + 1.18 +using namespace mozilla; 1.19 +using namespace mozilla::dom; 1.20 + 1.21 +bool XPCThrower::sVerbose = true; 1.22 + 1.23 +// static 1.24 +void 1.25 +XPCThrower::Throw(nsresult rv, JSContext* cx) 1.26 +{ 1.27 + const char* format; 1.28 + if (JS_IsExceptionPending(cx)) 1.29 + return; 1.30 + if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format)) 1.31 + format = ""; 1.32 + dom::Throw(cx, rv, format); 1.33 +} 1.34 + 1.35 +namespace xpc { 1.36 + 1.37 +bool 1.38 +Throw(JSContext *cx, nsresult rv) 1.39 +{ 1.40 + XPCThrower::Throw(rv, cx); 1.41 + return false; 1.42 +} 1.43 + 1.44 +} // namespace xpc 1.45 + 1.46 +/* 1.47 + * If there has already been an exception thrown, see if we're throwing the 1.48 + * same sort of exception, and if we are, don't clobber the old one. ccx 1.49 + * should be the current call context. 1.50 + */ 1.51 +// static 1.52 +bool 1.53 +XPCThrower::CheckForPendingException(nsresult result, JSContext *cx) 1.54 +{ 1.55 + nsCOMPtr<nsIException> e = XPCJSRuntime::Get()->GetPendingException(); 1.56 + if (!e) 1.57 + return false; 1.58 + XPCJSRuntime::Get()->SetPendingException(nullptr); 1.59 + 1.60 + nsresult e_result; 1.61 + if (NS_FAILED(e->GetResult(&e_result)) || e_result != result) 1.62 + return false; 1.63 + 1.64 + if (!ThrowExceptionObject(cx, e)) 1.65 + JS_ReportOutOfMemory(cx); 1.66 + return true; 1.67 +} 1.68 + 1.69 +// static 1.70 +void 1.71 +XPCThrower::Throw(nsresult rv, XPCCallContext& ccx) 1.72 +{ 1.73 + char* sz; 1.74 + const char* format; 1.75 + 1.76 + if (CheckForPendingException(rv, ccx)) 1.77 + return; 1.78 + 1.79 + if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format)) 1.80 + format = ""; 1.81 + 1.82 + sz = (char*) format; 1.83 + 1.84 + if (sz && sVerbose) 1.85 + Verbosify(ccx, &sz, false); 1.86 + 1.87 + dom::Throw(ccx, rv, sz); 1.88 + 1.89 + if (sz && sz != format) 1.90 + JS_smprintf_free(sz); 1.91 +} 1.92 + 1.93 + 1.94 +// static 1.95 +void 1.96 +XPCThrower::ThrowBadResult(nsresult rv, nsresult result, XPCCallContext& ccx) 1.97 +{ 1.98 + char* sz; 1.99 + const char* format; 1.100 + const char* name; 1.101 + 1.102 + /* 1.103 + * If there is a pending exception when the native call returns and 1.104 + * it has the same error result as returned by the native call, then 1.105 + * the native call may be passing through an error from a previous JS 1.106 + * call. So we'll just throw that exception into our JS. 1.107 + */ 1.108 + 1.109 + if (CheckForPendingException(result, ccx)) 1.110 + return; 1.111 + 1.112 + // else... 1.113 + 1.114 + if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format) || !format) 1.115 + format = ""; 1.116 + 1.117 + if (nsXPCException::NameAndFormatForNSResult(result, &name, nullptr) && name) 1.118 + sz = JS_smprintf("%s 0x%x (%s)", format, result, name); 1.119 + else 1.120 + sz = JS_smprintf("%s 0x%x", format, result); 1.121 + 1.122 + if (sz && sVerbose) 1.123 + Verbosify(ccx, &sz, true); 1.124 + 1.125 + dom::Throw(ccx, result, sz); 1.126 + 1.127 + if (sz) 1.128 + JS_smprintf_free(sz); 1.129 +} 1.130 + 1.131 +// static 1.132 +void 1.133 +XPCThrower::ThrowBadParam(nsresult rv, unsigned paramNum, XPCCallContext& ccx) 1.134 +{ 1.135 + char* sz; 1.136 + const char* format; 1.137 + 1.138 + if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format)) 1.139 + format = ""; 1.140 + 1.141 + sz = JS_smprintf("%s arg %d", format, paramNum); 1.142 + 1.143 + if (sz && sVerbose) 1.144 + Verbosify(ccx, &sz, true); 1.145 + 1.146 + dom::Throw(ccx, rv, sz); 1.147 + 1.148 + if (sz) 1.149 + JS_smprintf_free(sz); 1.150 +} 1.151 + 1.152 + 1.153 +// static 1.154 +void 1.155 +XPCThrower::Verbosify(XPCCallContext& ccx, 1.156 + char** psz, bool own) 1.157 +{ 1.158 + char* sz = nullptr; 1.159 + 1.160 + if (ccx.HasInterfaceAndMember()) { 1.161 + XPCNativeInterface* iface = ccx.GetInterface(); 1.162 + jsid id = ccx.GetMember()->GetName(); 1.163 + JSAutoByteString bytes; 1.164 + const char *name = JSID_IS_VOID(id) ? "Unknown" : bytes.encodeLatin1(ccx, JSID_TO_STRING(id)); 1.165 + if (!name) { 1.166 + name = ""; 1.167 + } 1.168 + sz = JS_smprintf("%s [%s.%s]", *psz, iface->GetNameString(), name); 1.169 + } 1.170 + 1.171 + if (sz) { 1.172 + if (own) 1.173 + JS_smprintf_free(*psz); 1.174 + *psz = sz; 1.175 + } 1.176 +}