Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* vim: set ts=8 sts=4 et sw=4 tw=99: */
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 "jsprf.h"
12 : #include "mozilla/dom/BindingUtils.h"
13 : #include "mozilla/dom/Exceptions.h"
14 : #include "nsStringGlue.h"
15 :
16 : using namespace mozilla;
17 : using namespace mozilla::dom;
18 :
19 : bool XPCThrower::sVerbose = true;
20 :
21 : // static
22 : void
23 0 : XPCThrower::Throw(nsresult rv, JSContext* cx)
24 : {
25 : const char* format;
26 0 : if (JS_IsExceptionPending(cx))
27 0 : return;
28 0 : if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format))
29 0 : format = "";
30 0 : dom::Throw(cx, rv, nsDependentCString(format));
31 : }
32 :
33 : namespace xpc {
34 :
35 : bool
36 0 : Throw(JSContext* cx, nsresult rv)
37 : {
38 0 : XPCThrower::Throw(rv, cx);
39 0 : 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
51 1978 : XPCThrower::CheckForPendingException(nsresult result, JSContext* cx)
52 : {
53 3956 : nsCOMPtr<nsIException> e = XPCJSContext::Get()->GetPendingException();
54 1978 : if (!e)
55 1978 : return false;
56 0 : XPCJSContext::Get()->SetPendingException(nullptr);
57 :
58 : nsresult e_result;
59 0 : if (NS_FAILED(e->GetResult(&e_result)) || e_result != result)
60 0 : return false;
61 :
62 0 : ThrowExceptionObject(cx, e);
63 0 : return true;
64 : }
65 :
66 : // static
67 : void
68 0 : XPCThrower::Throw(nsresult rv, XPCCallContext& ccx)
69 : {
70 : char* sz;
71 : const char* format;
72 :
73 0 : if (CheckForPendingException(rv, ccx))
74 0 : return;
75 :
76 0 : if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format))
77 0 : format = "";
78 :
79 0 : sz = (char*) format;
80 0 : NS_ENSURE_TRUE_VOID(sz);
81 :
82 0 : if (sz && sVerbose)
83 0 : Verbosify(ccx, &sz, false);
84 :
85 0 : dom::Throw(ccx, rv, nsDependentCString(sz));
86 :
87 0 : if (sz && sz != format)
88 0 : JS_smprintf_free(sz);
89 : }
90 :
91 :
92 : // static
93 : void
94 1978 : XPCThrower::ThrowBadResult(nsresult rv, nsresult result, XPCCallContext& ccx)
95 : {
96 : char* sz;
97 : const char* format;
98 : const char* name;
99 :
100 : /*
101 : * If there is a pending exception when the native call returns and
102 : * it has the same error result as returned by the native call, then
103 : * the native call may be passing through an error from a previous JS
104 : * call. So we'll just throw that exception into our JS. Note that
105 : * we don't need to worry about NS_ERROR_UNCATCHABLE_EXCEPTION,
106 : * because presumably there would be no pending exception for that
107 : * nsresult!
108 : */
109 :
110 1978 : if (CheckForPendingException(result, ccx))
111 0 : return;
112 :
113 : // else...
114 :
115 1978 : if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format) || !format)
116 0 : format = "";
117 :
118 1978 : if (nsXPCException::NameAndFormatForNSResult(result, &name, nullptr) && name)
119 75 : sz = JS_smprintf("%s 0x%x (%s)", format, (unsigned) result, name).release();
120 : else
121 1903 : sz = JS_smprintf("%s 0x%x", format, (unsigned) result).release();
122 1978 : NS_ENSURE_TRUE_VOID(sz);
123 :
124 1978 : if (sz && sVerbose)
125 1978 : Verbosify(ccx, &sz, true);
126 :
127 1978 : dom::Throw(ccx, result, nsDependentCString(sz));
128 :
129 1978 : if (sz)
130 1978 : JS_smprintf_free(sz);
131 : }
132 :
133 : // static
134 : void
135 0 : XPCThrower::ThrowBadParam(nsresult rv, unsigned paramNum, XPCCallContext& ccx)
136 : {
137 : char* sz;
138 : const char* format;
139 :
140 0 : if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format))
141 0 : format = "";
142 :
143 0 : sz = JS_smprintf("%s arg %d", format, paramNum).release();
144 0 : NS_ENSURE_TRUE_VOID(sz);
145 :
146 0 : if (sz && sVerbose)
147 0 : Verbosify(ccx, &sz, true);
148 :
149 0 : dom::Throw(ccx, rv, nsDependentCString(sz));
150 :
151 0 : if (sz)
152 0 : JS_smprintf_free(sz);
153 : }
154 :
155 :
156 : // static
157 : void
158 1978 : XPCThrower::Verbosify(XPCCallContext& ccx,
159 : char** psz, bool own)
160 : {
161 1978 : char* sz = nullptr;
162 :
163 1978 : if (ccx.HasInterfaceAndMember()) {
164 1978 : XPCNativeInterface* iface = ccx.GetInterface();
165 1978 : jsid id = ccx.GetMember()->GetName();
166 3956 : JSAutoByteString bytes;
167 1978 : const char* name = JSID_IS_VOID(id) ? "Unknown" : bytes.encodeLatin1(ccx, JSID_TO_STRING(id));
168 1978 : if (!name) {
169 0 : name = "";
170 : }
171 1978 : sz = JS_smprintf("%s [%s.%s]", *psz, iface->GetNameString(), name).release();
172 : }
173 :
174 1978 : if (sz) {
175 1978 : if (own)
176 1978 : JS_smprintf_free(*psz);
177 1978 : *psz = sz;
178 : }
179 1978 : }
|