1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sw=4 et tw=78:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is Mozilla Communicator client code, released
18 : * March 31, 1998.
19 : *
20 : * The Initial Developer of the Original Code is
21 : * Netscape Communications Corporation.
22 : * Portions created by the Initial Developer are Copyright (C) 1999
23 : * the Initial Developer. All Rights Reserved.
24 : *
25 : * Contributor(s):
26 : * John Bandhauer <jband@netscape.com> (original author)
27 : * Pierre Phaneuf <pp@ludusdesign.com>
28 : *
29 : * Alternatively, the contents of this file may be used under the terms of
30 : * either of the GNU General Public License Version 2 or later (the "GPL"),
31 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 : * in which case the provisions of the GPL or the LGPL are applicable instead
33 : * of those above. If you wish to allow use of your version of this file only
34 : * under the terms of either the GPL or the LGPL, and not to allow others to
35 : * use your version of this file under the terms of the MPL, indicate your
36 : * decision by deleting the provisions above and replace them with the notice
37 : * and other provisions required by the GPL or the LGPL. If you do not delete
38 : * the provisions above, a recipient may use your version of this file under
39 : * the terms of any one of the MPL, the GPL or the LGPL.
40 : *
41 : * ***** END LICENSE BLOCK ***** */
42 :
43 : /* Sharable code and data for wrapper around JSObjects. */
44 :
45 : #include "xpcprivate.h"
46 : #include "nsArrayEnumerator.h"
47 : #include "nsWrapperCache.h"
48 : #include "XPCWrapper.h"
49 : #include "AccessCheck.h"
50 : #include "nsJSUtils.h"
51 :
52 : #include "jsapi.h"
53 :
54 6654697 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsXPCWrappedJSClass, nsIXPCWrappedJSClass)
55 :
56 : // the value of this variable is never used - we use its address as a sentinel
57 : static uint32_t zero_methods_descriptor;
58 :
59 1520912 : bool AutoScriptEvaluate::StartEvaluating(JSObject *scope, JSErrorReporter errorReporter)
60 : {
61 1520912 : NS_PRECONDITION(!mEvaluated, "AutoScriptEvaluate::Evaluate should only be called once");
62 :
63 1520912 : if (!mJSContext)
64 0 : return true;
65 :
66 1520912 : mEvaluated = true;
67 1520912 : if (!JS_GetErrorReporter(mJSContext)) {
68 39 : JS_SetErrorReporter(mJSContext, errorReporter);
69 39 : mErrorReporterSet = true;
70 : }
71 :
72 1520912 : JS_BeginRequest(mJSContext);
73 1520912 : if (!mEnterCompartment.enter(mJSContext, scope))
74 0 : return false;
75 :
76 : // Saving the exception state keeps us from interfering with another script
77 : // that may also be running on this context. This occurred first with the
78 : // js debugger, as described in
79 : // http://bugzilla.mozilla.org/show_bug.cgi?id=88130 but presumably could
80 : // show up in any situation where a script calls into a wrapped js component
81 : // on the same context, while the context has a nonzero exception state.
82 : // Because JS_SaveExceptionState/JS_RestoreExceptionState use malloc
83 : // and addroot, we avoid them if possible by returning null (as opposed to
84 : // a JSExceptionState with no information) when there is no pending
85 : // exception.
86 1520912 : if (JS_IsExceptionPending(mJSContext)) {
87 1 : mState = JS_SaveExceptionState(mJSContext);
88 1 : JS_ClearPendingException(mJSContext);
89 : }
90 :
91 1520912 : return true;
92 : }
93 :
94 3041824 : AutoScriptEvaluate::~AutoScriptEvaluate()
95 : {
96 1520912 : if (!mJSContext || !mEvaluated)
97 : return;
98 1520912 : if (mState)
99 1 : JS_RestoreExceptionState(mJSContext, mState);
100 : else
101 1520911 : JS_ClearPendingException(mJSContext);
102 :
103 1520912 : JS_EndRequest(mJSContext);
104 :
105 : // If this is a JSContext that has a private context that provides a
106 : // nsIXPCScriptNotify interface, then notify the object the script has
107 : // been executed.
108 : //
109 : // Note: We rely on the rule that if any JSContext in our JSRuntime has
110 : // private data that points to an nsISupports subclass, it has also set
111 : // the JSOPTION_PRIVATE_IS_NSISUPPORTS option.
112 :
113 1520912 : if (JS_GetOptions(mJSContext) & JSOPTION_PRIVATE_IS_NSISUPPORTS) {
114 : nsCOMPtr<nsIXPCScriptNotify> scriptNotify =
115 : do_QueryInterface(static_cast<nsISupports*>
116 8 : (JS_GetContextPrivate(mJSContext)));
117 4 : if (scriptNotify)
118 0 : scriptNotify->ScriptExecuted();
119 : }
120 :
121 1520912 : if (mErrorReporterSet)
122 39 : JS_SetErrorReporter(mJSContext, NULL);
123 1520912 : }
124 :
125 : // It turns out that some errors may be not worth reporting. So, this
126 : // function is factored out to manage that.
127 6889 : JSBool xpc_IsReportableErrorCode(nsresult code)
128 : {
129 6889 : if (NS_SUCCEEDED(code))
130 1 : return false;
131 :
132 6888 : switch (code) {
133 : // Error codes that we don't want to report as errors...
134 : // These generally indicate bad interface design AFAIC.
135 : case NS_ERROR_FACTORY_REGISTER_AGAIN:
136 : case NS_BASE_STREAM_WOULD_BLOCK:
137 0 : return false;
138 : }
139 :
140 6888 : return true;
141 : }
142 :
143 : // static
144 : nsresult
145 156779 : nsXPCWrappedJSClass::GetNewOrUsed(XPCCallContext& ccx, REFNSIID aIID,
146 : nsXPCWrappedJSClass** resultClazz)
147 : {
148 156779 : nsXPCWrappedJSClass* clazz = nsnull;
149 156779 : XPCJSRuntime* rt = ccx.GetRuntime();
150 :
151 : { // scoped lock
152 313558 : XPCAutoLock lock(rt->GetMapLock());
153 156779 : IID2WrappedJSClassMap* map = rt->GetWrappedJSClassMap();
154 156779 : clazz = map->Find(aIID);
155 156779 : NS_IF_ADDREF(clazz);
156 : }
157 :
158 156779 : if (!clazz) {
159 65024 : nsCOMPtr<nsIInterfaceInfo> info;
160 32512 : ccx.GetXPConnect()->GetInfoForIID(&aIID, getter_AddRefs(info));
161 32512 : if (info) {
162 : bool canScript, isBuiltin;
163 130048 : if (NS_SUCCEEDED(info->IsScriptable(&canScript)) && canScript &&
164 65024 : NS_SUCCEEDED(info->IsBuiltinClass(&isBuiltin)) && !isBuiltin &&
165 32512 : nsXPConnect::IsISupportsDescendant(info)) {
166 65024 : clazz = new nsXPCWrappedJSClass(ccx, aIID, info);
167 32512 : if (clazz && !clazz->mDescriptors)
168 0 : NS_RELEASE(clazz); // sets clazz to nsnull
169 : }
170 : }
171 : }
172 156779 : *resultClazz = clazz;
173 156779 : return NS_OK;
174 : }
175 :
176 32512 : nsXPCWrappedJSClass::nsXPCWrappedJSClass(XPCCallContext& ccx, REFNSIID aIID,
177 : nsIInterfaceInfo* aInfo)
178 32512 : : mRuntime(ccx.GetRuntime()),
179 : mInfo(aInfo),
180 : mName(nsnull),
181 : mIID(aIID),
182 65024 : mDescriptors(nsnull)
183 : {
184 32512 : NS_ADDREF(mInfo);
185 32512 : NS_ADDREF_THIS();
186 :
187 : { // scoped lock
188 65024 : XPCAutoLock lock(mRuntime->GetMapLock());
189 32512 : mRuntime->GetWrappedJSClassMap()->Add(this);
190 : }
191 :
192 : uint16_t methodCount;
193 32512 : if (NS_SUCCEEDED(mInfo->GetMethodCount(&methodCount))) {
194 32512 : if (methodCount) {
195 32512 : int wordCount = (methodCount/32)+1;
196 65024 : if (nsnull != (mDescriptors = new uint32_t[wordCount])) {
197 : int i;
198 : // init flags to 0;
199 65124 : for (i = wordCount-1; i >= 0; i--)
200 32612 : mDescriptors[i] = 0;
201 :
202 431204 : for (i = 0; i < methodCount; i++) {
203 : const nsXPTMethodInfo* info;
204 183090 : if (NS_SUCCEEDED(mInfo->GetMethodInfo(i, &info)))
205 183090 : SetReflectable(i, XPCConvert::IsMethodReflectable(*info));
206 : else {
207 0 : delete [] mDescriptors;
208 0 : mDescriptors = nsnull;
209 0 : break;
210 : }
211 : }
212 : }
213 : } else {
214 0 : mDescriptors = &zero_methods_descriptor;
215 : }
216 : }
217 32512 : }
218 :
219 64996 : nsXPCWrappedJSClass::~nsXPCWrappedJSClass()
220 : {
221 32498 : if (mDescriptors && mDescriptors != &zero_methods_descriptor)
222 32498 : delete [] mDescriptors;
223 32498 : if (mRuntime)
224 : { // scoped lock
225 64996 : XPCAutoLock lock(mRuntime->GetMapLock());
226 32498 : mRuntime->GetWrappedJSClassMap()->Remove(this);
227 : }
228 32498 : if (mName)
229 2031 : nsMemory::Free(mName);
230 32498 : NS_IF_RELEASE(mInfo);
231 129992 : }
232 :
233 : JSObject*
234 295342 : nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(XPCCallContext& ccx,
235 : JSObject* jsobj,
236 : REFNSIID aIID)
237 : {
238 295342 : JSContext* cx = ccx.GetJSContext();
239 : JSObject* id;
240 : jsval retval;
241 : JSObject* retObj;
242 295342 : JSBool success = false;
243 : jsid funid;
244 : jsval fun;
245 :
246 : // Don't call the actual function on a content object. We'll determine
247 : // whether or not a content object is capable of implementing the
248 : // interface (i.e. whether the interface is scriptable) and most content
249 : // objects don't have QI implementations anyway. Also see bug 503926.
250 590684 : if (XPCPerThreadData::IsMainThread(ccx) &&
251 295342 : !xpc::AccessCheck::isChrome(js::GetObjectCompartment(jsobj))) {
252 0 : return nsnull;
253 : }
254 :
255 : // OK, it looks like we'll be calling into JS code.
256 590684 : AutoScriptEvaluate scriptEval(cx);
257 :
258 : // XXX we should install an error reporter that will send reports to
259 : // the JS error console service.
260 295342 : if (!scriptEval.StartEvaluating(jsobj))
261 0 : return nsnull;
262 :
263 : // check upfront for the existence of the function property
264 295342 : funid = mRuntime->GetStringID(XPCJSRuntime::IDX_QUERY_INTERFACE);
265 295342 : if (!JS_GetPropertyById(cx, jsobj, funid, &fun) || JSVAL_IS_PRIMITIVE(fun))
266 139437 : return nsnull;
267 :
268 : // protect fun so that we're sure it's alive when we call it
269 311810 : AUTO_MARK_JSVAL(ccx, fun);
270 :
271 : // Ensure that we are asking for a scriptable interface.
272 : // NB: It's important for security that this check is here rather
273 : // than later, since it prevents untrusted objects from implementing
274 : // some interfaces in JS and aggregating a trusted object to
275 : // implement intentionally (for security) unscriptable interfaces.
276 : // We so often ask for nsISupports that we can short-circuit the test...
277 155905 : if (!aIID.Equals(NS_GET_IID(nsISupports))) {
278 157042 : nsCOMPtr<nsIInterfaceInfo> info;
279 78521 : ccx.GetXPConnect()->GetInfoForIID(&aIID, getter_AddRefs(info));
280 78521 : if (!info)
281 55 : return nsnull;
282 : bool canScript, isBuiltin;
283 140520 : if (NS_FAILED(info->IsScriptable(&canScript)) || !canScript ||
284 62054 : NS_FAILED(info->IsBuiltinClass(&isBuiltin)) || isBuiltin)
285 16412 : return nsnull;
286 : }
287 :
288 139438 : id = xpc_NewIDObject(cx, jsobj, aIID);
289 139438 : if (id) {
290 : // Throwing NS_NOINTERFACE is the prescribed way to fail QI from JS. It
291 : // is not an exception that is ever worth reporting, but we don't want
292 : // to eat all exceptions either.
293 :
294 : uint32_t oldOpts =
295 139438 : JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_DONT_REPORT_UNCAUGHT);
296 :
297 139438 : jsval args[1] = {OBJECT_TO_JSVAL(id)};
298 139438 : success = JS_CallFunctionValue(cx, jsobj, fun, 1, args, &retval);
299 :
300 139438 : JS_SetOptions(cx, oldOpts);
301 :
302 139438 : if (!success) {
303 50703 : NS_ASSERTION(JS_IsExceptionPending(cx),
304 : "JS failed without setting an exception!");
305 :
306 50703 : jsval jsexception = JSVAL_NULL;
307 101406 : AUTO_MARK_JSVAL(ccx, &jsexception);
308 :
309 50703 : if (JS_GetPendingException(cx, &jsexception)) {
310 : nsresult rv;
311 50703 : if (JSVAL_IS_OBJECT(jsexception)) {
312 : // XPConnect may have constructed an object to represent a
313 : // C++ QI failure. See if that is the case.
314 730 : nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
315 :
316 365 : nsXPConnect::GetXPConnect()->
317 : GetWrappedNativeOfJSObject(ccx,
318 : JSVAL_TO_OBJECT(jsexception),
319 365 : getter_AddRefs(wrapper));
320 :
321 365 : if (wrapper) {
322 : nsCOMPtr<nsIException> exception =
323 0 : do_QueryWrappedNative(wrapper);
324 0 : if (exception &&
325 0 : NS_SUCCEEDED(exception->GetResult(&rv)) &&
326 : rv == NS_NOINTERFACE) {
327 0 : JS_ClearPendingException(cx);
328 : }
329 : }
330 50338 : } else if (JSVAL_IS_NUMBER(jsexception)) {
331 : // JS often throws an nsresult.
332 50338 : if (JSVAL_IS_DOUBLE(jsexception))
333 50338 : rv = (nsresult)(JSVAL_TO_DOUBLE(jsexception));
334 : else
335 0 : rv = (nsresult)(JSVAL_TO_INT(jsexception));
336 :
337 50338 : if (rv == NS_NOINTERFACE)
338 50338 : JS_ClearPendingException(cx);
339 : }
340 : }
341 :
342 : // Don't report if reporting was disabled by someone else.
343 50703 : if (!(oldOpts & JSOPTION_DONT_REPORT_UNCAUGHT))
344 11463 : JS_ReportPendingException(cx);
345 : }
346 : }
347 :
348 139438 : if (success)
349 88735 : success = JS_ValueToObject(cx, retval, &retObj);
350 :
351 139438 : return success ? retObj : nsnull;
352 : }
353 :
354 : /***************************************************************************/
355 :
356 : static JSBool
357 6 : GetNamedPropertyAsVariantRaw(XPCCallContext& ccx,
358 : JSObject* aJSObj,
359 : jsid aName,
360 : nsIVariant** aResult,
361 : nsresult* pErr)
362 : {
363 6 : nsXPTType type = nsXPTType((uint8_t)TD_INTERFACE_TYPE);
364 : jsval val;
365 :
366 6 : return JS_GetPropertyById(ccx, aJSObj, aName, &val) &&
367 : // Note that this always takes the T_INTERFACE path through
368 : // JSData2Native, so the value passed for useAllocator
369 : // doesn't really matter. We pass true for consistency.
370 : XPCConvert::JSData2Native(ccx, aResult, val, type, true,
371 6 : &NS_GET_IID(nsIVariant), pErr);
372 : }
373 :
374 : // static
375 : nsresult
376 6 : nsXPCWrappedJSClass::GetNamedPropertyAsVariant(XPCCallContext& ccx,
377 : JSObject* aJSObj,
378 : const nsAString& aName,
379 : nsIVariant** aResult)
380 : {
381 6 : JSContext* cx = ccx.GetJSContext();
382 : JSBool ok;
383 : jsid id;
384 6 : nsresult rv = NS_ERROR_FAILURE;
385 :
386 12 : AutoScriptEvaluate scriptEval(cx);
387 6 : if (!scriptEval.StartEvaluating(aJSObj))
388 0 : return NS_ERROR_FAILURE;
389 :
390 : // Wrap the string in a jsval after the AutoScriptEvaluate, so that the
391 : // resulting value ends up in the correct compartment.
392 : nsStringBuffer* buf;
393 6 : jsval jsstr = XPCStringConvert::ReadableToJSVal(ccx, aName, &buf);
394 6 : if (JSVAL_IS_NULL(jsstr))
395 0 : return NS_ERROR_OUT_OF_MEMORY;
396 6 : if (buf)
397 0 : buf->AddRef();
398 :
399 6 : ok = JS_ValueToId(cx, jsstr, &id) &&
400 6 : GetNamedPropertyAsVariantRaw(ccx, aJSObj, id, aResult, &rv);
401 :
402 6 : return ok ? NS_OK : NS_FAILED(rv) ? rv : NS_ERROR_FAILURE;
403 : }
404 :
405 : /***************************************************************************/
406 :
407 : // static
408 : nsresult
409 0 : nsXPCWrappedJSClass::BuildPropertyEnumerator(XPCCallContext& ccx,
410 : JSObject* aJSObj,
411 : nsISimpleEnumerator** aEnumerate)
412 : {
413 0 : JSContext* cx = ccx.GetJSContext();
414 :
415 0 : AutoScriptEvaluate scriptEval(cx);
416 0 : if (!scriptEval.StartEvaluating(aJSObj))
417 0 : return NS_ERROR_FAILURE;
418 :
419 0 : JS::AutoIdArray idArray(cx, JS_Enumerate(cx, aJSObj));
420 0 : if (!idArray)
421 0 : return NS_ERROR_FAILURE;
422 :
423 0 : nsCOMArray<nsIProperty> propertyArray(idArray.length());
424 0 : for (size_t i = 0; i < idArray.length(); i++) {
425 0 : jsid idName = idArray[i];
426 :
427 0 : nsCOMPtr<nsIVariant> value;
428 : nsresult rv;
429 0 : if (!GetNamedPropertyAsVariantRaw(ccx, aJSObj, idName,
430 0 : getter_AddRefs(value), &rv)) {
431 0 : if (NS_FAILED(rv))
432 0 : return rv;
433 0 : return NS_ERROR_FAILURE;
434 : }
435 :
436 : jsval jsvalName;
437 0 : if (!JS_IdToValue(cx, idName, &jsvalName))
438 0 : return NS_ERROR_FAILURE;
439 :
440 0 : JSString* name = JS_ValueToString(cx, jsvalName);
441 0 : if (!name)
442 0 : return NS_ERROR_FAILURE;
443 :
444 : size_t length;
445 0 : const jschar *chars = JS_GetStringCharsAndLength(cx, name, &length);
446 0 : if (!chars)
447 0 : return NS_ERROR_FAILURE;
448 :
449 : nsCOMPtr<nsIProperty> property =
450 0 : new xpcProperty(chars, (PRUint32) length, value);
451 :
452 0 : if (!propertyArray.AppendObject(property))
453 0 : return NS_ERROR_FAILURE;
454 : }
455 :
456 0 : return NS_NewArrayEnumerator(aEnumerate, propertyArray);
457 : }
458 :
459 : /***************************************************************************/
460 :
461 0 : NS_IMPL_ISUPPORTS1(xpcProperty, nsIProperty)
462 :
463 0 : xpcProperty::xpcProperty(const PRUnichar* aName, PRUint32 aNameLen,
464 : nsIVariant* aValue)
465 0 : : mName(aName, aNameLen), mValue(aValue)
466 : {
467 0 : }
468 :
469 : /* readonly attribute AString name; */
470 0 : NS_IMETHODIMP xpcProperty::GetName(nsAString & aName)
471 : {
472 0 : aName.Assign(mName);
473 0 : return NS_OK;
474 : }
475 :
476 : /* readonly attribute nsIVariant value; */
477 0 : NS_IMETHODIMP xpcProperty::GetValue(nsIVariant * *aValue)
478 : {
479 0 : NS_ADDREF(*aValue = mValue);
480 0 : return NS_OK;
481 : }
482 :
483 : /***************************************************************************/
484 : // This 'WrappedJSIdentity' class and singleton allow us to figure out if
485 : // any given nsISupports* is implemented by a WrappedJS object. This is done
486 : // using a QueryInterface call on the interface pointer with our ID. If
487 : // that call returns NS_OK and the pointer is to our singleton, then the
488 : // interface must be implemented by a WrappedJS object. NOTE: the
489 : // 'WrappedJSIdentity' object is not a real XPCOM object and should not be
490 : // used for anything else (hence it is declared in this implementation file).
491 :
492 : // {5C5C3BB0-A9BA-11d2-BA64-00805F8A5DD7}
493 : #define NS_IXPCONNECT_WRAPPED_JS_IDENTITY_CLASS_IID \
494 : { 0x5c5c3bb0, 0xa9ba, 0x11d2, \
495 : { 0xba, 0x64, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } }
496 :
497 : class WrappedJSIdentity
498 : {
499 : // no instance methods...
500 : public:
501 : NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXPCONNECT_WRAPPED_JS_IDENTITY_CLASS_IID)
502 :
503 34156 : static void* GetSingleton()
504 : {
505 : static WrappedJSIdentity* singleton = nsnull;
506 34156 : if (!singleton)
507 556 : singleton = new WrappedJSIdentity();
508 34156 : return (void*) singleton;
509 : }
510 : };
511 :
512 : NS_DEFINE_STATIC_IID_ACCESSOR(WrappedJSIdentity,
513 : NS_IXPCONNECT_WRAPPED_JS_IDENTITY_CLASS_IID)
514 :
515 : /***************************************************************************/
516 :
517 : // static
518 : JSBool
519 1225340 : nsXPCWrappedJSClass::IsWrappedJS(nsISupports* aPtr)
520 : {
521 : void* result;
522 1225340 : NS_PRECONDITION(aPtr, "null pointer");
523 : return aPtr &&
524 1225340 : NS_OK == aPtr->QueryInterface(NS_GET_IID(WrappedJSIdentity), &result) &&
525 2450680 : result == WrappedJSIdentity::GetSingleton();
526 : }
527 :
528 : static JSContext *
529 1849649 : GetContextFromObject(JSObject *obj)
530 : {
531 : // Don't stomp over a running context.
532 : XPCJSContextStack* stack =
533 1849649 : XPCPerThreadData::GetData(nsnull)->GetJSContextStack();
534 :
535 1849649 : if (stack && stack->Peek())
536 1755358 : return nsnull;
537 :
538 : // In order to get a context, we need a context.
539 188582 : XPCCallContext ccx(NATIVE_CALLER);
540 94291 : if (!ccx.IsValid())
541 0 : return nsnull;
542 :
543 188582 : JSAutoEnterCompartment ac;
544 94291 : if (!ac.enter(ccx, obj))
545 0 : return nsnull;
546 : XPCWrappedNativeScope* scope =
547 94291 : XPCWrappedNativeScope::FindInJSObjectScope(ccx, obj);
548 94291 : XPCContext *xpcc = scope->GetContext();
549 :
550 94291 : if (xpcc) {
551 94253 : JSContext *cx = xpcc->GetJSContext();
552 94253 : JS_AbortIfWrongThread(JS_GetRuntime(cx));
553 94253 : return cx;
554 : }
555 :
556 38 : return nsnull;
557 : }
558 :
559 : class SameOriginCheckedComponent : public nsISecurityCheckedComponent
560 0 : {
561 : public:
562 0 : SameOriginCheckedComponent(nsXPCWrappedJS* delegate)
563 0 : : mDelegate(delegate)
564 0 : {}
565 :
566 : NS_DECL_ISUPPORTS
567 : NS_DECL_NSISECURITYCHECKEDCOMPONENT
568 :
569 : private:
570 : nsRefPtr<nsXPCWrappedJS> mDelegate;
571 : };
572 :
573 0 : NS_IMPL_ADDREF(SameOriginCheckedComponent)
574 0 : NS_IMPL_RELEASE(SameOriginCheckedComponent)
575 :
576 0 : NS_INTERFACE_MAP_BEGIN(SameOriginCheckedComponent)
577 0 : NS_INTERFACE_MAP_ENTRY(nsISecurityCheckedComponent)
578 0 : NS_INTERFACE_MAP_END_AGGREGATED(mDelegate)
579 :
580 : NS_IMETHODIMP
581 0 : SameOriginCheckedComponent::CanCreateWrapper(const nsIID * iid,
582 : char **_retval NS_OUTPARAM)
583 : {
584 : // XXX This doesn't actually work because nsScriptSecurityManager doesn't
585 : // know what to do with "sameOrigin" for canCreateWrapper.
586 0 : *_retval = NS_strdup("sameOrigin");
587 0 : return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
588 : }
589 :
590 : NS_IMETHODIMP
591 0 : SameOriginCheckedComponent::CanCallMethod(const nsIID * iid,
592 : const PRUnichar *methodName,
593 : char **_retval NS_OUTPARAM)
594 : {
595 0 : *_retval = NS_strdup("sameOrigin");
596 0 : return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
597 : }
598 :
599 : NS_IMETHODIMP
600 0 : SameOriginCheckedComponent::CanGetProperty(const nsIID * iid,
601 : const PRUnichar *propertyName,
602 : char **_retval NS_OUTPARAM)
603 : {
604 0 : *_retval = NS_strdup("sameOrigin");
605 0 : return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
606 : }
607 :
608 : NS_IMETHODIMP
609 0 : SameOriginCheckedComponent::CanSetProperty(const nsIID * iid,
610 : const PRUnichar *propertyName,
611 : char **_retval NS_OUTPARAM)
612 : {
613 0 : *_retval = NS_strdup("sameOrigin");
614 0 : return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
615 : }
616 :
617 : NS_IMETHODIMP
618 941967 : nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self,
619 : REFNSIID aIID,
620 : void** aInstancePtr)
621 : {
622 941967 : if (aIID.Equals(NS_GET_IID(nsIXPConnectJSObjectHolder))) {
623 0 : NS_ADDREF(self);
624 0 : *aInstancePtr = (void*) static_cast<nsIXPConnectJSObjectHolder*>(self);
625 0 : return NS_OK;
626 : }
627 :
628 : // Objects internal to xpconnect are the only objects that even know *how*
629 : // to ask for this iid. And none of them bother refcounting the thing.
630 941967 : if (aIID.Equals(NS_GET_IID(WrappedJSIdentity))) {
631 : // asking to find out if this is a wrapper object
632 17078 : *aInstancePtr = WrappedJSIdentity::GetSingleton();
633 17078 : return NS_OK;
634 : }
635 :
636 924889 : if (aIID.Equals(NS_GET_IID(nsIPropertyBag))) {
637 : // We only want to expose one implementation from our aggregate.
638 7 : nsXPCWrappedJS* root = self->GetRootWrapper();
639 :
640 7 : if (!root->IsValid()) {
641 0 : *aInstancePtr = nsnull;
642 0 : return NS_NOINTERFACE;
643 : }
644 :
645 7 : NS_ADDREF(root);
646 7 : *aInstancePtr = (void*) static_cast<nsIPropertyBag*>(root);
647 7 : return NS_OK;
648 : }
649 :
650 : // We can't have a cached wrapper.
651 924882 : if (aIID.Equals(NS_GET_IID(nsWrapperCache))) {
652 300802 : *aInstancePtr = nsnull;
653 300802 : return NS_NOINTERFACE;
654 : }
655 :
656 624080 : JSContext *context = GetContextFromObject(self->GetJSObject());
657 1248160 : XPCCallContext ccx(NATIVE_CALLER, context);
658 624080 : if (!ccx.IsValid()) {
659 0 : *aInstancePtr = nsnull;
660 0 : return NS_NOINTERFACE;
661 : }
662 :
663 : // We support nsISupportsWeakReference iff the root wrapped JSObject
664 : // claims to support it in its QueryInterface implementation.
665 624080 : if (aIID.Equals(NS_GET_IID(nsISupportsWeakReference))) {
666 : // We only want to expose one implementation from our aggregate.
667 5160 : nsXPCWrappedJS* root = self->GetRootWrapper();
668 :
669 : // Fail if JSObject doesn't claim support for nsISupportsWeakReference
670 10320 : if (!root->IsValid() ||
671 5160 : !CallQueryInterfaceOnJSObject(ccx, root->GetJSObject(), aIID)) {
672 1 : *aInstancePtr = nsnull;
673 1 : return NS_NOINTERFACE;
674 : }
675 :
676 5159 : NS_ADDREF(root);
677 5159 : *aInstancePtr = (void*) static_cast<nsISupportsWeakReference*>(root);
678 5159 : return NS_OK;
679 : }
680 :
681 : nsXPCWrappedJS* sibling;
682 :
683 : // Checks for any existing wrapper explicitly constructed for this iid.
684 : // This includes the current 'self' wrapper. This also deals with the
685 : // nsISupports case (for which it returns mRoot).
686 618920 : if (nsnull != (sibling = self->Find(aIID))) {
687 483276 : NS_ADDREF(sibling);
688 483276 : *aInstancePtr = sibling->GetXPTCStub();
689 483276 : return NS_OK;
690 : }
691 :
692 : // Check if asking for an interface from which one of our wrappers inherits.
693 135644 : if (nsnull != (sibling = self->FindInherited(aIID))) {
694 2241 : NS_ADDREF(sibling);
695 2241 : *aInstancePtr = sibling->GetXPTCStub();
696 2241 : return NS_OK;
697 : }
698 :
699 : // else we do the more expensive stuff...
700 :
701 : // Before calling out, ensure that we're not about to claim to implement
702 : // nsISecurityCheckedComponent for an untrusted object. Doing so causes
703 : // problems. See bug 352882.
704 : // But if this is a content object, then we might be wrapping it for
705 : // content. If our JS object isn't a double-wrapped object (that is, we
706 : // don't have XPCWrappedJS(XPCWrappedNative(some C++ object))), then it
707 : // definitely will not have classinfo (and therefore won't be a DOM
708 : // object). Since content wants to be able to use these objects (directly
709 : // or indirectly, see bug 483672), we implement nsISecurityCheckedComponent
710 : // for them and tell caps that they are also bound by the same origin
711 : // model.
712 :
713 133403 : if (aIID.Equals(NS_GET_IID(nsISecurityCheckedComponent))) {
714 : // XXX This code checks to see if the given object has chrome (also
715 : // known as system) principals. It really wants to do a
716 : // UniversalXPConnect type check.
717 :
718 2170 : *aInstancePtr = nsnull;
719 :
720 2170 : if (!XPCPerThreadData::IsMainThread(ccx.GetJSContext()))
721 0 : return NS_NOINTERFACE;
722 :
723 2170 : nsXPConnect *xpc = nsXPConnect::GetXPConnect();
724 : nsCOMPtr<nsIScriptSecurityManager> secMan =
725 4340 : do_QueryInterface(xpc->GetDefaultSecurityManager());
726 2170 : if (!secMan)
727 0 : return NS_NOINTERFACE;
728 :
729 2170 : JSObject *selfObj = self->GetJSObject();
730 4340 : nsCOMPtr<nsIPrincipal> objPrin;
731 2170 : nsresult rv = secMan->GetObjectPrincipal(ccx, selfObj,
732 2170 : getter_AddRefs(objPrin));
733 2170 : if (NS_FAILED(rv))
734 0 : return rv;
735 :
736 : bool isSystem;
737 2170 : rv = secMan->IsSystemPrincipal(objPrin, &isSystem);
738 2170 : if ((NS_FAILED(rv) || !isSystem) &&
739 0 : !IS_WRAPPER_CLASS(js::GetObjectClass(selfObj))) {
740 : // A content object.
741 : nsRefPtr<SameOriginCheckedComponent> checked =
742 0 : new SameOriginCheckedComponent(self);
743 0 : if (!checked)
744 0 : return NS_ERROR_OUT_OF_MEMORY;
745 0 : *aInstancePtr = checked.forget().get();
746 0 : return NS_OK;
747 : }
748 : }
749 :
750 : // check if the JSObject claims to implement this interface
751 : JSObject* jsobj = CallQueryInterfaceOnJSObject(ccx, self->GetJSObject(),
752 133403 : aIID);
753 133403 : if (jsobj) {
754 : // protect jsobj until it is actually attached
755 12754 : AUTO_MARK_JSVAL(ccx, OBJECT_TO_JSVAL(jsobj));
756 :
757 : // We can't use XPConvert::JSObject2NativeInterface() here
758 : // since that can find a XPCWrappedNative directly on the
759 : // proto chain, and we don't want that here. We need to find
760 : // the actual JS object that claimed it supports the interface
761 : // we're looking for or we'll potentially bypass security
762 : // checks etc by calling directly through to a native found on
763 : // the prototype chain.
764 : //
765 : // Instead, simply do the nsXPCWrappedJS part of
766 : // XPConvert::JSObject2NativeInterface() here to make sure we
767 : // get a new (or used) nsXPCWrappedJS.
768 : nsXPCWrappedJS* wrapper;
769 : nsresult rv = nsXPCWrappedJS::GetNewOrUsed(ccx, jsobj, aIID, nsnull,
770 6377 : &wrapper);
771 6377 : if (NS_SUCCEEDED(rv) && wrapper) {
772 : // We need to go through the QueryInterface logic to make
773 : // this return the right thing for the various 'special'
774 : // interfaces; e.g. nsIPropertyBag.
775 6377 : rv = wrapper->QueryInterface(aIID, aInstancePtr);
776 6377 : NS_RELEASE(wrapper);
777 6377 : return rv;
778 : }
779 : }
780 :
781 : // else...
782 : // no can do
783 127026 : *aInstancePtr = nsnull;
784 127026 : return NS_NOINTERFACE;
785 : }
786 :
787 : JSObject*
788 156775 : nsXPCWrappedJSClass::GetRootJSObject(XPCCallContext& ccx, JSObject* aJSObj)
789 : {
790 : JSObject* result = CallQueryInterfaceOnJSObject(ccx, aJSObj,
791 156775 : NS_GET_IID(nsISupports));
792 156775 : if (!result)
793 79579 : return aJSObj;
794 77196 : JSObject* inner = XPCWrapper::Unwrap(ccx, result);
795 77196 : if (inner)
796 0 : return inner;
797 77196 : return result;
798 : }
799 :
800 : void
801 0 : xpcWrappedJSErrorReporter(JSContext *cx, const char *message,
802 : JSErrorReport *report)
803 : {
804 0 : if (report) {
805 : // If it is an exception report, then we can just deal with the
806 : // exception later (if not caught in the JS code).
807 0 : if (JSREPORT_IS_EXCEPTION(report->flags)) {
808 : // XXX We have a problem with error reports from uncaught exceptions.
809 : //
810 : // http://bugzilla.mozilla.org/show_bug.cgi?id=66453
811 : //
812 : // The issue is...
813 : //
814 : // We can't assume that the exception will *stay* uncaught. So, if
815 : // we build an nsIXPCException here and the underlying exception
816 : // really is caught before our script is done running then we blow
817 : // it by returning failure to our caller when the script didn't
818 : // really fail. However, This report contains error location info
819 : // that is no longer available after the script is done. So, if the
820 : // exception really is not caught (and is a non-engine exception)
821 : // then we've lost the oportunity to capture the script location
822 : // info that we *could* have captured here.
823 : //
824 : // This is expecially an issue with nested evaluations.
825 : //
826 : // Perhaps we could capture an expception here and store it as
827 : // 'provisional' and then later if there is a pending exception
828 : // when the script is done then we could maybe compare that in some
829 : // way with the 'provisional' one in which we captured location info.
830 : // We would not want to assume that the one discovered here is the
831 : // same one that is later detected. This could cause us to lie.
832 : //
833 : // The thing is. we do not currently store the right stuff to compare
834 : // these two nsIXPCExceptions (triggered by the same exception jsval
835 : // in the engine). Maybe we should store the jsval and compare that?
836 : // Maybe without even rooting it since we will not dereference it.
837 : // This is inexact, but maybe the right thing to do?
838 : //
839 : // if (report->errorNumber == JSMSG_UNCAUGHT_EXCEPTION)) ...
840 : //
841 :
842 0 : return;
843 : }
844 :
845 0 : if (JSREPORT_IS_WARNING(report->flags)) {
846 : // XXX printf the warning (#ifdef DEBUG only!).
847 : // XXX send the warning to the console service.
848 0 : return;
849 : }
850 : }
851 :
852 0 : XPCCallContext ccx(NATIVE_CALLER, cx);
853 0 : if (!ccx.IsValid())
854 : return;
855 :
856 0 : nsCOMPtr<nsIException> e;
857 : XPCConvert::JSErrorToXPCException(ccx, message, nsnull, nsnull, report,
858 0 : getter_AddRefs(e));
859 0 : if (e)
860 0 : ccx.GetXPCContext()->SetException(e);
861 : }
862 :
863 : JSBool
864 1821 : nsXPCWrappedJSClass::GetArraySizeFromParam(JSContext* cx,
865 : const XPTMethodDescriptor* method,
866 : const nsXPTParamInfo& param,
867 : uint16_t methodIndex,
868 : uint8_t paramIndex,
869 : nsXPTCMiniVariant* nativeParams,
870 : uint32_t* result)
871 : {
872 : uint8_t argnum;
873 : nsresult rv;
874 :
875 1821 : rv = mInfo->GetSizeIsArgNumberForParam(methodIndex, ¶m, 0, &argnum);
876 1821 : if (NS_FAILED(rv))
877 0 : return false;
878 :
879 1821 : const nsXPTParamInfo& arg_param = method->params[argnum];
880 1821 : const nsXPTType& arg_type = arg_param.GetType();
881 :
882 : // This should be enforced by the xpidl compiler, but it's not.
883 : // See bug 695235.
884 1821 : NS_ABORT_IF_FALSE(arg_type.TagPart() == nsXPTType::T_U32,
885 : "size_is references parameter of invalid type.");
886 :
887 1821 : if (arg_param.IsIndirect())
888 1733 : *result = *(uint32_t*)nativeParams[argnum].val.p;
889 : else
890 88 : *result = nativeParams[argnum].val.u32;
891 :
892 1821 : return true;
893 : }
894 :
895 : JSBool
896 377406 : nsXPCWrappedJSClass::GetInterfaceTypeFromParam(JSContext* cx,
897 : const XPTMethodDescriptor* method,
898 : const nsXPTParamInfo& param,
899 : uint16_t methodIndex,
900 : const nsXPTType& type,
901 : nsXPTCMiniVariant* nativeParams,
902 : nsID* result)
903 : {
904 377406 : uint8_t type_tag = type.TagPart();
905 :
906 377406 : if (type_tag == nsXPTType::T_INTERFACE) {
907 367862 : if (NS_SUCCEEDED(GetInterfaceInfo()->
908 : GetIIDForParamNoAlloc(methodIndex, ¶m, result))) {
909 367862 : return true;
910 : }
911 9544 : } else if (type_tag == nsXPTType::T_INTERFACE_IS) {
912 : uint8_t argnum;
913 : nsresult rv;
914 : rv = mInfo->GetInterfaceIsArgNumberForParam(methodIndex,
915 9544 : ¶m, &argnum);
916 9544 : if (NS_FAILED(rv))
917 0 : return false;
918 :
919 9544 : const nsXPTParamInfo& arg_param = method->params[argnum];
920 9544 : const nsXPTType& arg_type = arg_param.GetType();
921 :
922 9544 : if (arg_type.TagPart() == nsXPTType::T_IID) {
923 9544 : if (arg_param.IsIndirect()) {
924 6 : nsID** p = (nsID**) nativeParams[argnum].val.p;
925 6 : if (!p || !*p)
926 0 : return false;
927 6 : *result = **p;
928 : } else {
929 9538 : nsID* p = (nsID*) nativeParams[argnum].val.p;
930 9538 : if (!p)
931 0 : return false;
932 9538 : *result = *p;
933 : }
934 9544 : return true;
935 : }
936 : }
937 0 : return false;
938 : }
939 :
940 : void
941 4 : nsXPCWrappedJSClass::CleanupPointerArray(const nsXPTType& datum_type,
942 : uint32_t array_count,
943 : void** arrayp)
944 : {
945 4 : if (datum_type.IsInterfacePointer()) {
946 2 : nsISupports** pp = (nsISupports**) arrayp;
947 11 : for (uint32_t k = 0; k < array_count; k++) {
948 9 : nsISupports* p = pp[k];
949 9 : NS_IF_RELEASE(p);
950 : }
951 : } else {
952 2 : void** pp = (void**) arrayp;
953 16 : for (uint32_t k = 0; k < array_count; k++) {
954 14 : void* p = pp[k];
955 14 : if (p) nsMemory::Free(p);
956 : }
957 : }
958 4 : }
959 :
960 : void
961 34 : nsXPCWrappedJSClass::CleanupPointerTypeObject(const nsXPTType& type,
962 : void** pp)
963 : {
964 34 : NS_ASSERTION(pp,"null pointer");
965 34 : if (type.IsInterfacePointer()) {
966 2 : nsISupports* p = *((nsISupports**)pp);
967 2 : if (p) p->Release();
968 : } else {
969 32 : void* p = *((void**)pp);
970 32 : if (p) nsMemory::Free(p);
971 : }
972 34 : }
973 :
974 : class AutoClearPendingException
975 : {
976 : public:
977 6889 : AutoClearPendingException(JSContext *cx) : mCx(cx) { }
978 6889 : ~AutoClearPendingException() { JS_ClearPendingException(mCx); }
979 : private:
980 : JSContext* mCx;
981 : };
982 :
983 : nsresult
984 6889 : nsXPCWrappedJSClass::CheckForException(XPCCallContext & ccx,
985 : const char * aPropertyName,
986 : const char * anInterfaceName,
987 : bool aForceReport)
988 : {
989 6889 : XPCContext * xpcc = ccx.GetXPCContext();
990 6889 : JSContext * cx = ccx.GetJSContext();
991 13778 : nsCOMPtr<nsIException> xpc_exception;
992 : /* this one would be set by our error reporter */
993 :
994 6889 : xpcc->GetException(getter_AddRefs(xpc_exception));
995 6889 : if (xpc_exception)
996 88 : xpcc->SetException(nsnull);
997 :
998 : // get this right away in case we do something below to cause JS code
999 : // to run on this JSContext
1000 6889 : nsresult pending_result = xpcc->GetPendingResult();
1001 :
1002 : jsval js_exception;
1003 6889 : JSBool is_js_exception = JS_GetPendingException(cx, &js_exception);
1004 :
1005 : /* JS might throw an expection whether the reporter was called or not */
1006 6889 : if (is_js_exception) {
1007 6801 : if (!xpc_exception)
1008 : XPCConvert::JSValToXPCException(ccx, js_exception, anInterfaceName,
1009 : aPropertyName,
1010 6801 : getter_AddRefs(xpc_exception));
1011 :
1012 : /* cleanup and set failed even if we can't build an exception */
1013 6801 : if (!xpc_exception) {
1014 0 : ccx.GetThreadData()->SetException(nsnull); // XXX necessary?
1015 : }
1016 : }
1017 :
1018 13778 : AutoClearPendingException acpe(cx);
1019 :
1020 6889 : if (xpc_exception) {
1021 : nsresult e_result;
1022 6889 : if (NS_SUCCEEDED(xpc_exception->GetResult(&e_result))) {
1023 : // Figure out whether or not we should report this exception.
1024 6889 : bool reportable = xpc_IsReportableErrorCode(e_result);
1025 6889 : if (reportable) {
1026 : // Always want to report forced exceptions and XPConnect's own
1027 : // errors.
1028 : reportable = aForceReport ||
1029 6888 : NS_ERROR_GET_MODULE(e_result) == NS_ERROR_MODULE_XPCONNECT;
1030 :
1031 : // See if an environment variable was set or someone has told us
1032 : // that a user pref was set indicating that we should report all
1033 : // exceptions.
1034 6888 : if (!reportable)
1035 6434 : reportable = nsXPConnect::ReportAllJSExceptions();
1036 :
1037 : // Finally, check to see if this is the last JS frame on the
1038 : // stack. If so then we always want to report it.
1039 6888 : if (!reportable) {
1040 6434 : bool onlyNativeStackFrames = true;
1041 6434 : JSStackFrame * fp = nsnull;
1042 12868 : while ((fp = JS_FrameIterator(cx, &fp))) {
1043 2082 : if (JS_IsScriptFrame(cx, fp)) {
1044 2082 : onlyNativeStackFrames = false;
1045 2082 : break;
1046 : }
1047 : }
1048 6434 : reportable = onlyNativeStackFrames;
1049 : }
1050 :
1051 : // Ugly special case for GetInterface. It's "special" in the
1052 : // same way as QueryInterface in that a failure is not
1053 : // exceptional and shouldn't be reported. We have to do this
1054 : // check here instead of in xpcwrappedjs (like we do for QI) to
1055 : // avoid adding extra code to all xpcwrappedjs objects.
1056 14991 : if (reportable && e_result == NS_ERROR_NO_INTERFACE &&
1057 4052 : !strcmp(anInterfaceName, "nsIInterfaceRequestor") &&
1058 4051 : !strcmp(aPropertyName, "getInterface")) {
1059 4051 : reportable = false;
1060 : }
1061 : }
1062 :
1063 : // Try to use the error reporter set on the context to handle this
1064 : // error if it came from a JS exception.
1065 7556 : if (reportable && is_js_exception &&
1066 667 : JS_GetErrorReporter(cx) != xpcWrappedJSErrorReporter) {
1067 667 : reportable = !JS_ReportPendingException(cx);
1068 : }
1069 :
1070 6889 : if (reportable) {
1071 : #ifdef DEBUG
1072 : static const char line[] =
1073 : "************************************************************\n";
1074 : static const char preamble[] =
1075 : "* Call to xpconnect wrapped JSObject produced this error: *\n";
1076 : static const char cant_get_text[] =
1077 : "FAILED TO GET TEXT FROM EXCEPTION\n";
1078 :
1079 88 : fputs(line, stdout);
1080 88 : fputs(preamble, stdout);
1081 : char* text;
1082 88 : if (NS_SUCCEEDED(xpc_exception->ToString(&text)) && text) {
1083 88 : fputs(text, stdout);
1084 88 : fputs("\n", stdout);
1085 88 : nsMemory::Free(text);
1086 : } else
1087 0 : fputs(cant_get_text, stdout);
1088 88 : fputs(line, stdout);
1089 : #endif
1090 :
1091 : // Log the exception to the JS Console, so that users can do
1092 : // something with it.
1093 : nsCOMPtr<nsIConsoleService> consoleService
1094 176 : (do_GetService(XPC_CONSOLE_CONTRACTID));
1095 88 : if (nsnull != consoleService) {
1096 : nsresult rv;
1097 176 : nsCOMPtr<nsIScriptError> scriptError;
1098 176 : nsCOMPtr<nsISupports> errorData;
1099 88 : rv = xpc_exception->GetData(getter_AddRefs(errorData));
1100 88 : if (NS_SUCCEEDED(rv))
1101 88 : scriptError = do_QueryInterface(errorData);
1102 :
1103 88 : if (nsnull == scriptError) {
1104 : // No luck getting one from the exception, so
1105 : // try to cook one up.
1106 88 : scriptError = do_CreateInstance(XPC_SCRIPT_ERROR_CONTRACTID);
1107 88 : if (nsnull != scriptError) {
1108 : char* exn_string;
1109 88 : rv = xpc_exception->ToString(&exn_string);
1110 88 : if (NS_SUCCEEDED(rv)) {
1111 : // use toString on the exception as the message
1112 176 : nsAutoString newMessage;
1113 88 : newMessage.AssignWithConversion(exn_string);
1114 88 : nsMemory::Free((void *) exn_string);
1115 :
1116 : // try to get filename, lineno from the first
1117 : // stack frame location.
1118 88 : PRInt32 lineNumber = 0;
1119 176 : nsXPIDLCString sourceName;
1120 :
1121 176 : nsCOMPtr<nsIStackFrame> location;
1122 88 : xpc_exception->
1123 88 : GetLocation(getter_AddRefs(location));
1124 88 : if (location) {
1125 : // Get line number w/o checking; 0 is ok.
1126 16 : location->GetLineNumber(&lineNumber);
1127 :
1128 : // get a filename.
1129 16 : rv = location->GetFilename(getter_Copies(sourceName));
1130 : }
1131 :
1132 88 : rv = scriptError->InitWithWindowID(newMessage.get(),
1133 88 : NS_ConvertASCIItoUTF16(sourceName).get(),
1134 : nsnull,
1135 : lineNumber, 0, 0,
1136 : "XPConnect JavaScript",
1137 88 : nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx));
1138 88 : if (NS_FAILED(rv))
1139 0 : scriptError = nsnull;
1140 : }
1141 : }
1142 : }
1143 88 : if (nsnull != scriptError)
1144 88 : consoleService->LogMessage(scriptError);
1145 : }
1146 : }
1147 : // Whether or not it passes the 'reportable' test, it might
1148 : // still be an error and we have to do the right thing here...
1149 6889 : if (NS_FAILED(e_result)) {
1150 6888 : ccx.GetThreadData()->SetException(xpc_exception);
1151 6888 : return e_result;
1152 : }
1153 : }
1154 : } else {
1155 : // see if JS code signaled failure result without throwing exception
1156 0 : if (NS_FAILED(pending_result)) {
1157 0 : return pending_result;
1158 : }
1159 : }
1160 1 : return NS_ERROR_FAILURE;
1161 : }
1162 :
1163 : class ContextPrincipalGuard
1164 : {
1165 : nsIScriptSecurityManager *ssm;
1166 : XPCCallContext &ccx;
1167 : public:
1168 1225564 : ContextPrincipalGuard(XPCCallContext &ccx)
1169 1225564 : : ssm(nsnull), ccx(ccx) {}
1170 1225564 : void principalPushed(nsIScriptSecurityManager *ssm) { this->ssm = ssm; }
1171 1225564 : ~ContextPrincipalGuard() { if (ssm) ssm->PopContextPrincipal(ccx); }
1172 : };
1173 :
1174 : NS_IMETHODIMP
1175 1225569 : nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
1176 : const XPTMethodDescriptor* info,
1177 : nsXPTCMiniVariant* nativeParams)
1178 : {
1179 1225569 : jsval* sp = nsnull;
1180 1225569 : jsval* argv = nsnull;
1181 : uint8_t i;
1182 1225569 : nsresult retval = NS_ERROR_FAILURE;
1183 1225569 : nsresult pending_result = NS_OK;
1184 : JSBool success;
1185 1225569 : JSBool readyToDoTheCall = false;
1186 : nsID param_iid;
1187 1225569 : const char* name = info->name;
1188 : jsval fval;
1189 : JSBool foundDependentParam;
1190 :
1191 : // Make sure not to set the callee on ccx until after we've gone through
1192 : // the whole nsIXPCFunctionThisTranslator bit. That code uses ccx to
1193 : // convert natives to JSObjects, but we do NOT plan to pass those JSObjects
1194 : // to our real callee.
1195 1225569 : JSContext *context = GetContextFromObject(wrapper->GetJSObject());
1196 2451138 : XPCCallContext ccx(NATIVE_CALLER, context);
1197 1225569 : if (!ccx.IsValid())
1198 0 : return retval;
1199 :
1200 1225569 : XPCContext *xpcc = ccx.GetXPCContext();
1201 1225569 : JSContext *cx = ccx.GetJSContext();
1202 :
1203 1225569 : if (!cx || !xpcc || !IsReflectable(methodIndex))
1204 5 : return NS_ERROR_FAILURE;
1205 :
1206 1225564 : JSObject *obj = wrapper->GetJSObject();
1207 1225564 : JSObject *thisObj = obj;
1208 :
1209 2451128 : JSAutoEnterCompartment ac;
1210 1225564 : if (!ac.enter(cx, obj))
1211 0 : return NS_ERROR_FAILURE;
1212 :
1213 1225564 : ccx.SetScopeForNewJSObjects(obj);
1214 :
1215 2451128 : JS::AutoValueVector args(cx);
1216 2451128 : AutoScriptEvaluate scriptEval(cx);
1217 2451128 : ContextPrincipalGuard principalGuard(ccx);
1218 :
1219 : // XXX ASSUMES that retval is last arg. The xpidl compiler ensures this.
1220 1225564 : uint8_t paramCount = info->num_args;
1221 : uint8_t argc = paramCount -
1222 1225564 : (paramCount && XPT_PD_IS_RETVAL(info->params[paramCount-1].flags) ? 1 : 0);
1223 :
1224 1225564 : if (!scriptEval.StartEvaluating(obj, xpcWrappedJSErrorReporter))
1225 0 : goto pre_call_clean_up;
1226 :
1227 1225564 : xpcc->SetPendingResult(pending_result);
1228 1225564 : xpcc->SetException(nsnull);
1229 1225564 : ccx.GetThreadData()->SetException(nsnull);
1230 :
1231 1225564 : if (XPCPerThreadData::IsMainThread(ccx)) {
1232 : // TODO Remove me in favor of security wrappers.
1233 1225564 : nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
1234 1225564 : if (ssm) {
1235 : nsIPrincipal *objPrincipal =
1236 1225564 : xpc::AccessCheck::getPrincipal(js::GetObjectCompartment(obj));
1237 1225564 : if (objPrincipal) {
1238 1225564 : JSStackFrame* fp = nsnull;
1239 : nsresult rv =
1240 : ssm->PushContextPrincipal(ccx, JS_FrameIterator(ccx, &fp),
1241 1225564 : objPrincipal);
1242 1225564 : if (NS_FAILED(rv)) {
1243 0 : JS_ReportOutOfMemory(ccx);
1244 0 : retval = NS_ERROR_OUT_OF_MEMORY;
1245 0 : goto pre_call_clean_up;
1246 : }
1247 :
1248 1225564 : principalGuard.principalPushed(ssm);
1249 : }
1250 : }
1251 : }
1252 :
1253 : // We use js_Invoke so that the gcthings we use as args will be rooted by
1254 : // the engine as we do conversions and prepare to do the function call.
1255 :
1256 : // setup stack
1257 :
1258 : // if this isn't a function call then we don't need to push extra stuff
1259 1225564 : if (!(XPT_MD_IS_SETTER(info->flags) || XPT_MD_IS_GETTER(info->flags))) {
1260 : // We get fval before allocating the stack to avoid gc badness that can
1261 : // happen if the GetProperty call leaves our request and the gc runs
1262 : // while the stack we allocate contains garbage.
1263 :
1264 : // If the interface is marked as a [function] then we will assume that
1265 : // our JSObject is a function and not an object with a named method.
1266 :
1267 : bool isFunction;
1268 441283 : if (NS_FAILED(mInfo->IsFunction(&isFunction)))
1269 0 : goto pre_call_clean_up;
1270 :
1271 : // In the xpidl [function] case we are making sure now that the
1272 : // JSObject is callable. If it is *not* callable then we silently
1273 : // fallback to looking up the named property...
1274 : // (because jst says he thinks this fallback is 'The Right Thing'.)
1275 : //
1276 : // In the normal (non-function) case we just lookup the property by
1277 : // name and as long as the object has such a named property we go ahead
1278 : // and try to make the call. If it turns out the named property is not
1279 : // a callable object then the JS engine will throw an error and we'll
1280 : // pass this along to the caller as an exception/result code.
1281 :
1282 499466 : if (isFunction &&
1283 58183 : JS_TypeOfValue(ccx, OBJECT_TO_JSVAL(obj)) == JSTYPE_FUNCTION) {
1284 11962 : fval = OBJECT_TO_JSVAL(obj);
1285 :
1286 : // We may need to translate the 'this' for the function object.
1287 :
1288 11962 : if (paramCount) {
1289 10315 : const nsXPTParamInfo& firstParam = info->params[0];
1290 10315 : if (firstParam.IsIn()) {
1291 10315 : const nsXPTType& firstType = firstParam.GetType();
1292 :
1293 10315 : if (firstType.IsInterfacePointer()) {
1294 : nsIXPCFunctionThisTranslator* translator;
1295 :
1296 : IID2ThisTranslatorMap* map =
1297 7466 : mRuntime->GetThisTranslatorMap();
1298 :
1299 : {
1300 14932 : XPCAutoLock lock(mRuntime->GetMapLock()); // scoped lock
1301 7466 : translator = map->Find(mIID);
1302 : }
1303 :
1304 7466 : if (translator) {
1305 3965 : bool hideFirstParamFromJS = false;
1306 3965 : nsIID* newWrapperIID = nsnull;
1307 7930 : nsCOMPtr<nsISupports> newThis;
1308 :
1309 3965 : if (NS_FAILED(translator->
1310 : TranslateThis((nsISupports*)nativeParams[0].val.p,
1311 : mInfo, methodIndex,
1312 : &hideFirstParamFromJS,
1313 : &newWrapperIID,
1314 : getter_AddRefs(newThis)))) {
1315 : goto pre_call_clean_up;
1316 : }
1317 3965 : if (hideFirstParamFromJS) {
1318 0 : NS_ERROR("HideFirstParamFromJS not supported");
1319 : goto pre_call_clean_up;
1320 : }
1321 3965 : if (newThis) {
1322 : jsval v;
1323 7930 : xpcObjectHelper helper(newThis);
1324 : JSBool ok =
1325 : XPCConvert::NativeInterface2JSObject(ccx,
1326 : &v, nsnull, helper, newWrapperIID,
1327 3965 : nsnull, false, nsnull);
1328 3965 : if (newWrapperIID)
1329 0 : nsMemory::Free(newWrapperIID);
1330 3965 : if (!ok) {
1331 : goto pre_call_clean_up;
1332 : }
1333 3965 : thisObj = JSVAL_TO_OBJECT(v);
1334 3965 : if (!JS_WrapObject(cx, &thisObj))
1335 : goto pre_call_clean_up;
1336 : }
1337 : }
1338 : }
1339 : }
1340 : }
1341 429321 : } else if (!JS_GetMethod(cx, obj, name, &thisObj, &fval)) {
1342 : // XXX We really want to factor out the error reporting better and
1343 : // specifically report the failure to find a function with this name.
1344 : // This is what we do below if the property is found but is not a
1345 : // function. We just need to factor better so we can get to that
1346 : // reporting path from here.
1347 0 : goto pre_call_clean_up;
1348 : }
1349 : }
1350 :
1351 1225564 : if (!args.resize(argc)) {
1352 0 : retval = NS_ERROR_OUT_OF_MEMORY;
1353 0 : goto pre_call_clean_up;
1354 : }
1355 :
1356 1225564 : argv = args.begin();
1357 1225564 : sp = argv;
1358 :
1359 : // build the args
1360 : // NB: This assignment *looks* wrong because we haven't yet called our
1361 : // function. However, we *have* already entered the compartmen that we're
1362 : // about to call, and that's the global that we want here. In other words:
1363 : // we're trusting the JS engine to come up with a good global to use for
1364 : // our object (whatever it was).
1365 1915856 : for (i = 0; i < argc; i++) {
1366 690292 : const nsXPTParamInfo& param = info->params[i];
1367 690292 : const nsXPTType& type = param.GetType();
1368 690292 : nsXPTType datum_type;
1369 : uint32_t array_count;
1370 690292 : bool isArray = type.IsArray();
1371 690292 : jsval val = JSVAL_NULL;
1372 1380584 : AUTO_MARK_JSVAL(ccx, &val);
1373 : bool isSizedString = isArray ?
1374 : false :
1375 690198 : type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
1376 1380490 : type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS;
1377 :
1378 :
1379 : // verify that null was not passed for 'out' param
1380 690292 : if (param.IsOut() && !nativeParams[i].val.p) {
1381 0 : retval = NS_ERROR_INVALID_ARG;
1382 : goto pre_call_clean_up;
1383 : }
1384 :
1385 690292 : if (isArray) {
1386 94 : if (NS_FAILED(mInfo->GetTypeForParam(methodIndex, ¶m, 1,
1387 : &datum_type)))
1388 : goto pre_call_clean_up;
1389 : } else
1390 690198 : datum_type = type;
1391 :
1392 690292 : if (param.IsIn()) {
1393 : nsXPTCMiniVariant* pv;
1394 :
1395 682119 : if (param.IsIndirect())
1396 187 : pv = (nsXPTCMiniVariant*) nativeParams[i].val.p;
1397 : else
1398 681932 : pv = &nativeParams[i];
1399 :
1400 1048790 : if (datum_type.IsInterfacePointer() &&
1401 : !GetInterfaceTypeFromParam(cx, info, param, methodIndex,
1402 : datum_type, nativeParams,
1403 366671 : ¶m_iid))
1404 : goto pre_call_clean_up;
1405 :
1406 682119 : if (isArray || isSizedString) {
1407 98 : if (!GetArraySizeFromParam(cx, info, param, methodIndex,
1408 98 : i, nativeParams, &array_count))
1409 : goto pre_call_clean_up;
1410 : }
1411 :
1412 682119 : if (isArray) {
1413 188 : XPCLazyCallContext lccx(ccx);
1414 94 : if (!XPCConvert::NativeArray2JS(lccx, &val,
1415 : (const void**)&pv->val,
1416 : datum_type, ¶m_iid,
1417 94 : array_count, nsnull))
1418 : goto pre_call_clean_up;
1419 682025 : } else if (isSizedString) {
1420 4 : if (!XPCConvert::NativeStringWithSize2JS(ccx, &val,
1421 : (const void*)&pv->val,
1422 : datum_type,
1423 4 : array_count, nsnull))
1424 : goto pre_call_clean_up;
1425 : } else {
1426 682021 : if (!XPCConvert::NativeData2JS(ccx, &val, &pv->val, type,
1427 682021 : ¶m_iid, nsnull))
1428 : goto pre_call_clean_up;
1429 : }
1430 : }
1431 :
1432 690292 : if (param.IsOut() || param.IsDipper()) {
1433 : // create an 'out' object
1434 8246 : JSObject* out_obj = NewOutObject(cx, obj);
1435 8246 : if (!out_obj) {
1436 0 : retval = NS_ERROR_OUT_OF_MEMORY;
1437 : goto pre_call_clean_up;
1438 : }
1439 :
1440 8246 : if (param.IsIn()) {
1441 73 : if (!JS_SetPropertyById(cx, out_obj,
1442 73 : mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
1443 73 : &val)) {
1444 : goto pre_call_clean_up;
1445 : }
1446 : }
1447 8246 : *sp++ = OBJECT_TO_JSVAL(out_obj);
1448 : } else
1449 682046 : *sp++ = val;
1450 : }
1451 :
1452 1225564 : readyToDoTheCall = true;
1453 :
1454 : pre_call_clean_up:
1455 : // clean up any 'out' params handed in
1456 2963861 : for (i = 0; i < paramCount; i++) {
1457 1738297 : const nsXPTParamInfo& param = info->params[i];
1458 1738297 : if (!param.IsOut())
1459 1423283 : continue;
1460 :
1461 315014 : const nsXPTType& type = param.GetType();
1462 315014 : if (!type.deprecated_IsPointer())
1463 286902 : continue;
1464 : void* p;
1465 28112 : if (!(p = nativeParams[i].val.p))
1466 0 : continue;
1467 :
1468 28112 : if (param.IsIn()) {
1469 42 : if (type.IsArray()) {
1470 : void** pp;
1471 8 : if (nsnull != (pp = *((void***)p))) {
1472 :
1473 : // we need to get the array length and iterate the items
1474 : uint32_t array_count;
1475 8 : nsXPTType datum_type;
1476 :
1477 20 : if (NS_SUCCEEDED(mInfo->GetTypeForParam(methodIndex, ¶m,
1478 : 1, &datum_type)) &&
1479 8 : datum_type.deprecated_IsPointer() &&
1480 : GetArraySizeFromParam(cx, info, param, methodIndex,
1481 4 : i, nativeParams, &array_count) &&
1482 : array_count) {
1483 :
1484 4 : CleanupPointerArray(datum_type, array_count, pp);
1485 : }
1486 :
1487 : // always release the array if it is inout
1488 8 : nsMemory::Free(pp);
1489 : }
1490 : } else
1491 34 : CleanupPointerTypeObject(type, (void**)p);
1492 : }
1493 28112 : *((void**)p) = nsnull;
1494 : }
1495 :
1496 : // Make sure "this" doesn't get deleted during this call.
1497 2451128 : nsCOMPtr<nsIXPCWrappedJSClass> kungFuDeathGrip(this);
1498 :
1499 1225564 : if (!readyToDoTheCall)
1500 0 : return retval;
1501 :
1502 : // do the deed - note exceptions
1503 :
1504 1225564 : JS_ClearPendingException(cx);
1505 :
1506 : jsval rval;
1507 1225564 : if (XPT_MD_IS_GETTER(info->flags)) {
1508 758452 : success = JS_GetProperty(cx, obj, name, argv);
1509 758452 : rval = *argv;
1510 467112 : } else if (XPT_MD_IS_SETTER(info->flags)) {
1511 25829 : success = JS_SetProperty(cx, obj, name, argv);
1512 25829 : rval = *argv;
1513 : } else {
1514 441283 : if (!JSVAL_IS_PRIMITIVE(fval)) {
1515 441195 : uint32_t oldOpts = JS_GetOptions(cx);
1516 441195 : JS_SetOptions(cx, oldOpts | JSOPTION_DONT_REPORT_UNCAUGHT);
1517 :
1518 441195 : success = JS_CallFunctionValue(cx, thisObj, fval, argc, argv, &rval);
1519 :
1520 441195 : JS_SetOptions(cx, oldOpts);
1521 : } else {
1522 : // The property was not an object so can't be a function.
1523 : // Let's build and 'throw' an exception.
1524 :
1525 : static const nsresult code =
1526 : NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED;
1527 : static const char format[] = "%s \"%s\"";
1528 : const char * msg;
1529 88 : char* sz = nsnull;
1530 :
1531 88 : if (nsXPCException::NameAndFormatForNSResult(code, nsnull, &msg) && msg)
1532 88 : sz = JS_smprintf(format, msg, name);
1533 :
1534 176 : nsCOMPtr<nsIException> e;
1535 :
1536 : XPCConvert::ConstructException(code, sz, GetInterfaceName(), name,
1537 88 : nsnull, getter_AddRefs(e), nsnull, nsnull);
1538 88 : xpcc->SetException(e);
1539 88 : if (sz)
1540 88 : JS_smprintf_free(sz);
1541 88 : success = false;
1542 : }
1543 : }
1544 :
1545 1225564 : if (!success) {
1546 : bool forceReport;
1547 6889 : if (NS_FAILED(mInfo->IsFunction(&forceReport)))
1548 0 : forceReport = false;
1549 :
1550 : // May also want to check if we're moving from content->chrome and force
1551 : // a report in that case.
1552 :
1553 6889 : return CheckForException(ccx, name, GetInterfaceName(), forceReport);
1554 : }
1555 :
1556 1218675 : ccx.GetThreadData()->SetException(nsnull); // XXX necessary?
1557 :
1558 : // convert out args and result
1559 : // NOTE: this is the total number of native params, not just the args
1560 : // Convert independent params only.
1561 : // When we later convert the dependent params (if any) we will know that
1562 : // the params upon which they depend will have already been converted -
1563 : // regardless of ordering.
1564 :
1565 1218675 : foundDependentParam = false;
1566 2941699 : for (i = 0; i < paramCount; i++) {
1567 1723024 : const nsXPTParamInfo& param = info->params[i];
1568 1723024 : NS_ABORT_IF_FALSE(!param.IsShared(), "[shared] implies [noscript]!");
1569 1723024 : if (!param.IsOut() && !param.IsDipper())
1570 674512 : continue;
1571 :
1572 1048512 : const nsXPTType& type = param.GetType();
1573 1048512 : if (type.IsDependent()) {
1574 11257 : foundDependentParam = true;
1575 11257 : continue;
1576 : }
1577 :
1578 : jsval val;
1579 1037255 : uint8_t type_tag = type.TagPart();
1580 : nsXPTCMiniVariant* pv;
1581 :
1582 1037255 : if (param.IsDipper())
1583 741169 : pv = (nsXPTCMiniVariant*) &nativeParams[i].val.p;
1584 : else
1585 296086 : pv = (nsXPTCMiniVariant*) nativeParams[i].val.p;
1586 :
1587 1037255 : if (param.IsRetval())
1588 1030341 : val = rval;
1589 13828 : else if (JSVAL_IS_PRIMITIVE(argv[i]) ||
1590 6914 : !JS_GetPropertyById(cx, JSVAL_TO_OBJECT(argv[i]),
1591 6914 : mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
1592 13828 : &val))
1593 0 : break;
1594 :
1595 : // setup allocator and/or iid
1596 :
1597 1037255 : if (type_tag == nsXPTType::T_INTERFACE) {
1598 10431 : if (NS_FAILED(GetInterfaceInfo()->
1599 : GetIIDForParamNoAlloc(methodIndex, ¶m,
1600 : ¶m_iid)))
1601 0 : break;
1602 : }
1603 :
1604 1037255 : if (!XPCConvert::JSData2Native(ccx, &pv->val, val, type,
1605 1037255 : !param.IsDipper(), ¶m_iid, nsnull))
1606 0 : break;
1607 : }
1608 :
1609 : // if any params were dependent, then we must iterate again to convert them.
1610 1218675 : if (foundDependentParam && i == paramCount) {
1611 45388 : for (i = 0; i < paramCount; i++) {
1612 34142 : const nsXPTParamInfo& param = info->params[i];
1613 34142 : if (!param.IsOut())
1614 21162 : continue;
1615 :
1616 12980 : const nsXPTType& type = param.GetType();
1617 12980 : if (!type.IsDependent())
1618 1723 : continue;
1619 :
1620 : jsval val;
1621 : nsXPTCMiniVariant* pv;
1622 11257 : nsXPTType datum_type;
1623 : uint32_t array_count;
1624 11257 : bool isArray = type.IsArray();
1625 : bool isSizedString = isArray ?
1626 : false :
1627 9542 : type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
1628 20799 : type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS;
1629 :
1630 11257 : pv = (nsXPTCMiniVariant*) nativeParams[i].val.p;
1631 :
1632 11257 : if (param.IsRetval())
1633 11246 : val = rval;
1634 22 : else if (!JS_GetPropertyById(cx, JSVAL_TO_OBJECT(argv[i]),
1635 11 : mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
1636 22 : &val))
1637 0 : break;
1638 :
1639 : // setup allocator and/or iid
1640 :
1641 11257 : if (isArray) {
1642 1715 : if (NS_FAILED(mInfo->GetTypeForParam(methodIndex, ¶m, 1,
1643 : &datum_type)))
1644 0 : break;
1645 : } else
1646 9542 : datum_type = type;
1647 :
1648 11257 : if (datum_type.IsInterfacePointer()) {
1649 10735 : if (!GetInterfaceTypeFromParam(cx, info, param, methodIndex,
1650 : datum_type, nativeParams,
1651 10735 : ¶m_iid))
1652 0 : break;
1653 : }
1654 :
1655 11257 : if (isArray || isSizedString) {
1656 1719 : if (!GetArraySizeFromParam(cx, info, param, methodIndex,
1657 1719 : i, nativeParams, &array_count))
1658 0 : break;
1659 : }
1660 :
1661 11257 : if (isArray) {
1662 2178 : if (array_count &&
1663 : !XPCConvert::JSArray2Native(ccx, (void**)&pv->val, val,
1664 : array_count, datum_type,
1665 463 : ¶m_iid, nsnull))
1666 0 : break;
1667 9542 : } else if (isSizedString) {
1668 4 : if (!XPCConvert::JSStringWithSize2Native(ccx,
1669 : (void*)&pv->val, val,
1670 : array_count, datum_type,
1671 4 : nsnull))
1672 0 : break;
1673 : } else {
1674 9538 : if (!XPCConvert::JSData2Native(ccx, &pv->val, val, type,
1675 : true, ¶m_iid,
1676 9538 : nsnull))
1677 0 : break;
1678 : }
1679 : }
1680 : }
1681 :
1682 1218675 : if (i != paramCount) {
1683 : // We didn't manage all the result conversions!
1684 : // We have to cleanup any junk that *did* get converted.
1685 :
1686 0 : for (uint8_t k = 0; k < i; k++) {
1687 0 : const nsXPTParamInfo& param = info->params[k];
1688 0 : if (!param.IsOut())
1689 0 : continue;
1690 0 : const nsXPTType& type = param.GetType();
1691 0 : if (!type.deprecated_IsPointer())
1692 0 : continue;
1693 : void* p;
1694 0 : if (!(p = nativeParams[k].val.p))
1695 0 : continue;
1696 :
1697 0 : if (type.IsArray()) {
1698 : void** pp;
1699 0 : if (nsnull != (pp = *((void***)p))) {
1700 : // we need to get the array length and iterate the items
1701 : uint32_t array_count;
1702 0 : nsXPTType datum_type;
1703 :
1704 0 : if (NS_SUCCEEDED(mInfo->GetTypeForParam(methodIndex, ¶m,
1705 : 1, &datum_type)) &&
1706 0 : datum_type.deprecated_IsPointer() &&
1707 : GetArraySizeFromParam(cx, info, param, methodIndex,
1708 0 : k, nativeParams, &array_count) &&
1709 : array_count) {
1710 :
1711 0 : CleanupPointerArray(datum_type, array_count, pp);
1712 : }
1713 0 : nsMemory::Free(pp);
1714 : }
1715 : } else
1716 0 : CleanupPointerTypeObject(type, (void**)p);
1717 0 : *((void**)p) = nsnull;
1718 : }
1719 : } else {
1720 : // set to whatever the JS code might have set as the result
1721 1218675 : retval = pending_result;
1722 : }
1723 :
1724 1218675 : return retval;
1725 : }
1726 :
1727 : const char*
1728 6978 : nsXPCWrappedJSClass::GetInterfaceName()
1729 : {
1730 6978 : if (!mName)
1731 2032 : mInfo->GetName(&mName);
1732 6978 : return mName;
1733 : }
1734 :
1735 : JSObject*
1736 8246 : nsXPCWrappedJSClass::NewOutObject(JSContext* cx, JSObject* scope)
1737 : {
1738 8246 : return JS_NewObject(cx, nsnull, nsnull, JS_GetGlobalForObject(cx, scope));
1739 : }
1740 :
1741 :
1742 : NS_IMETHODIMP
1743 0 : nsXPCWrappedJSClass::DebugDump(PRInt16 depth)
1744 : {
1745 : #ifdef DEBUG
1746 0 : depth-- ;
1747 0 : XPC_LOG_ALWAYS(("nsXPCWrappedJSClass @ %x with mRefCnt = %d", this, mRefCnt.get()));
1748 0 : XPC_LOG_INDENT();
1749 : char* name;
1750 0 : mInfo->GetName(&name);
1751 0 : XPC_LOG_ALWAYS(("interface name is %s", name));
1752 0 : if (name)
1753 0 : nsMemory::Free(name);
1754 0 : char * iid = mIID.ToString();
1755 0 : XPC_LOG_ALWAYS(("IID number is %s", iid ? iid : "invalid"));
1756 0 : if (iid)
1757 0 : NS_Free(iid);
1758 0 : XPC_LOG_ALWAYS(("InterfaceInfo @ %x", mInfo));
1759 0 : uint16_t methodCount = 0;
1760 0 : if (depth) {
1761 : uint16_t i;
1762 0 : nsCOMPtr<nsIInterfaceInfo> parent;
1763 0 : XPC_LOG_INDENT();
1764 0 : mInfo->GetParent(getter_AddRefs(parent));
1765 0 : XPC_LOG_ALWAYS(("parent @ %x", parent.get()));
1766 0 : mInfo->GetMethodCount(&methodCount);
1767 0 : XPC_LOG_ALWAYS(("MethodCount = %d", methodCount));
1768 0 : mInfo->GetConstantCount(&i);
1769 0 : XPC_LOG_ALWAYS(("ConstantCount = %d", i));
1770 0 : XPC_LOG_OUTDENT();
1771 : }
1772 0 : XPC_LOG_ALWAYS(("mRuntime @ %x", mRuntime));
1773 0 : XPC_LOG_ALWAYS(("mDescriptors @ %x count = %d", mDescriptors, methodCount));
1774 0 : if (depth && mDescriptors && methodCount) {
1775 0 : depth--;
1776 0 : XPC_LOG_INDENT();
1777 0 : for (uint16_t i = 0; i < methodCount; i++) {
1778 0 : XPC_LOG_ALWAYS(("Method %d is %s%s", \
1779 : i, IsReflectable(i) ? "":" NOT ","reflectable"));
1780 : }
1781 0 : XPC_LOG_OUTDENT();
1782 0 : depth++;
1783 : }
1784 0 : XPC_LOG_OUTDENT();
1785 : #endif
1786 0 : return NS_OK;
1787 : }
|