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 : /* JavaScript JSClasses and JSOps for our Wrapped Native JS Objects. */
8 :
9 : #include "xpcprivate.h"
10 : #include "xpc_make_class.h"
11 : #include "jsprf.h"
12 : #include "mozilla/dom/BindingUtils.h"
13 : #include "mozilla/Preferences.h"
14 : #include "nsIAddonInterposition.h"
15 : #include "AddonWrapper.h"
16 : #include "js/Class.h"
17 :
18 : using namespace mozilla;
19 : using namespace JS;
20 :
21 : /***************************************************************************/
22 :
23 : // All of the exceptions thrown into JS from this file go through here.
24 : // That makes this a nice place to set a breakpoint.
25 :
26 0 : static bool Throw(nsresult errNum, JSContext* cx)
27 : {
28 0 : XPCThrower::Throw(errNum, cx);
29 0 : return false;
30 : }
31 :
32 : // Handy macro used in many callback stub below.
33 :
34 : #define THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper) \
35 : PR_BEGIN_MACRO \
36 : if (!wrapper) \
37 : return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); \
38 : if (!wrapper->IsValid()) \
39 : return Throw(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN, cx); \
40 : PR_END_MACRO
41 :
42 : /***************************************************************************/
43 :
44 : static bool
45 8 : ToStringGuts(XPCCallContext& ccx)
46 : {
47 16 : UniqueChars sz;
48 8 : XPCWrappedNative* wrapper = ccx.GetWrapper();
49 :
50 8 : if (wrapper)
51 8 : sz.reset(wrapper->ToString(ccx.GetTearOff()));
52 : else
53 0 : sz = JS_smprintf("[xpconnect wrapped native prototype]");
54 :
55 8 : if (!sz) {
56 0 : JS_ReportOutOfMemory(ccx);
57 0 : return false;
58 : }
59 :
60 8 : JSString* str = JS_NewStringCopyZ(ccx, sz.get());
61 8 : if (!str)
62 0 : return false;
63 :
64 8 : ccx.SetRetVal(JS::StringValue(str));
65 8 : return true;
66 : }
67 :
68 : /***************************************************************************/
69 :
70 : static bool
71 0 : XPC_WN_Shared_ToString(JSContext* cx, unsigned argc, Value* vp)
72 : {
73 0 : CallArgs args = CallArgsFromVp(argc, vp);
74 0 : RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
75 0 : if (!obj)
76 0 : return false;
77 :
78 0 : XPCCallContext ccx(cx, obj);
79 0 : if (!ccx.IsValid())
80 0 : return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
81 0 : ccx.SetName(ccx.GetContext()->GetStringID(XPCJSContext::IDX_TO_STRING));
82 0 : ccx.SetArgsAndResultPtr(args.length(), args.array(), vp);
83 0 : return ToStringGuts(ccx);
84 : }
85 :
86 : static bool
87 0 : XPC_WN_Shared_ToSource(JSContext* cx, unsigned argc, Value* vp)
88 : {
89 0 : CallArgs args = CallArgsFromVp(argc, vp);
90 : static const char empty[] = "({})";
91 0 : JSString* str = JS_NewStringCopyN(cx, empty, sizeof(empty)-1);
92 0 : if (!str)
93 0 : return false;
94 0 : args.rval().setString(str);
95 :
96 0 : return true;
97 : }
98 :
99 : static bool
100 852 : XPC_WN_Shared_toPrimitive(JSContext* cx, unsigned argc, Value* vp)
101 : {
102 852 : CallArgs args = CallArgsFromVp(argc, vp);
103 :
104 1704 : RootedObject obj(cx);
105 852 : if (!JS_ValueToObject(cx, args.thisv(), &obj))
106 0 : return false;
107 1704 : XPCCallContext ccx(cx, obj);
108 852 : XPCWrappedNative* wrapper = ccx.GetWrapper();
109 852 : THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
110 :
111 : JSType hint;
112 852 : if (!GetFirstArgumentAsTypeHint(cx, args, &hint))
113 0 : return false;
114 :
115 852 : if (hint == JSTYPE_NUMBER) {
116 0 : args.rval().set(JS_GetNaNValue(cx));
117 0 : return true;
118 : }
119 :
120 852 : MOZ_ASSERT(hint == JSTYPE_STRING || hint == JSTYPE_UNDEFINED);
121 852 : ccx.SetName(ccx.GetContext()->GetStringID(XPCJSContext::IDX_TO_STRING));
122 852 : ccx.SetArgsAndResultPtr(0, nullptr, args.rval().address());
123 :
124 852 : XPCNativeMember* member = ccx.GetMember();
125 852 : if (member && member->IsMethod()) {
126 844 : if (!XPCWrappedNative::CallMethod(ccx))
127 0 : return false;
128 :
129 844 : if (args.rval().isPrimitive())
130 844 : return true;
131 : }
132 :
133 : // else...
134 8 : return ToStringGuts(ccx);
135 : }
136 :
137 : /***************************************************************************/
138 :
139 : // A "double wrapped object" is a user JSObject that has been wrapped as a
140 : // wrappedJS in order to be used by native code and then re-wrapped by a
141 : // wrappedNative wrapper to be used by JS code. One might think of it as:
142 : // wrappedNative(wrappedJS(underlying_JSObject))
143 : // This is done (as opposed to just unwrapping the wrapped JS and automatically
144 : // returning the underlying JSObject) so that JS callers will see what looks
145 : // Like any other xpcom object - and be limited to use its interfaces.
146 : //
147 : // See the comment preceding nsIXPCWrappedJSObjectGetter in nsIXPConnect.idl.
148 :
149 : static JSObject*
150 6 : GetDoubleWrappedJSObject(XPCCallContext& ccx, XPCWrappedNative* wrapper)
151 : {
152 12 : RootedObject obj(ccx);
153 : nsCOMPtr<nsIXPConnectWrappedJS>
154 12 : underware = do_QueryInterface(wrapper->GetIdentityObject());
155 6 : if (underware) {
156 12 : RootedObject mainObj(ccx, underware->GetJSObject());
157 6 : if (mainObj) {
158 : RootedId id(ccx, ccx.GetContext()->
159 12 : GetStringID(XPCJSContext::IDX_WRAPPED_JSOBJECT));
160 :
161 12 : JSAutoCompartment ac(ccx, mainObj);
162 :
163 12 : RootedValue val(ccx);
164 12 : if (JS_GetPropertyById(ccx, mainObj, id, &val) &&
165 6 : !val.isPrimitive()) {
166 6 : obj = val.toObjectOrNull();
167 : }
168 : }
169 : }
170 12 : return obj;
171 : }
172 :
173 : // This is the getter native function we use to handle 'wrappedJSObject' for
174 : // double wrapped JSObjects.
175 :
176 : static bool
177 3 : XPC_WN_DoubleWrappedGetter(JSContext* cx, unsigned argc, Value* vp)
178 : {
179 3 : CallArgs args = CallArgsFromVp(argc, vp);
180 :
181 6 : RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
182 3 : if (!obj)
183 0 : return false;
184 :
185 6 : XPCCallContext ccx(cx, obj);
186 3 : XPCWrappedNative* wrapper = ccx.GetWrapper();
187 3 : THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
188 :
189 3 : MOZ_ASSERT(JS_TypeOfValue(cx, args.calleev()) == JSTYPE_FUNCTION, "bad function");
190 :
191 6 : RootedObject realObject(cx, GetDoubleWrappedJSObject(ccx, wrapper));
192 3 : if (!realObject) {
193 : // This is pretty unexpected at this point. The object originally
194 : // responded to this get property call and now gives no object.
195 : // XXX Should this throw something at the caller?
196 0 : args.rval().setNull();
197 0 : return true;
198 : }
199 :
200 : // It is a double wrapped object. This should really never appear in
201 : // content these days, but addons still do it - see bug 965921.
202 3 : if (MOZ_UNLIKELY(!nsContentUtils::IsSystemCaller(cx))) {
203 0 : JS_ReportErrorASCII(cx, "Attempt to use .wrappedJSObject in untrusted code");
204 0 : return false;
205 : }
206 3 : args.rval().setObject(*realObject);
207 3 : return JS_WrapValue(cx, args.rval());
208 : }
209 :
210 : /***************************************************************************/
211 :
212 : // This is our shared function to define properties on our JSObjects.
213 :
214 : /*
215 : * NOTE:
216 : * We *never* set the tearoff names (e.g. nsIFoo) as JS_ENUMERATE.
217 : * We *never* set toString or toSource as JS_ENUMERATE.
218 : */
219 :
220 : static bool
221 5576 : DefinePropertyIfFound(XPCCallContext& ccx,
222 : HandleObject obj,
223 : HandleId idArg,
224 : XPCNativeSet* set,
225 : XPCNativeInterface* ifaceArg,
226 : XPCNativeMember* member,
227 : XPCWrappedNativeScope* scope,
228 : bool reflectToStringAndToSource,
229 : XPCWrappedNative* wrapperToReflectInterfaceNames,
230 : XPCWrappedNative* wrapperToReflectDoubleWrap,
231 : nsIXPCScriptable* scr,
232 : unsigned propFlags,
233 : bool* resolved)
234 : {
235 11152 : RootedId id(ccx, idArg);
236 11152 : RefPtr<XPCNativeInterface> iface = ifaceArg;
237 5576 : XPCJSContext* xpccx = ccx.GetContext();
238 : bool found;
239 : const char* name;
240 :
241 5576 : propFlags |= JSPROP_RESOLVING;
242 :
243 5576 : if (set) {
244 5576 : if (iface)
245 298 : found = true;
246 : else
247 5278 : found = set->FindMember(id, &member, &iface);
248 : } else
249 0 : found = (nullptr != (member = iface->FindMember(id)));
250 :
251 5576 : if (!found) {
252 2768 : if (reflectToStringAndToSource) {
253 : JSNative call;
254 2768 : uint32_t flags = 0;
255 :
256 2768 : if (scr) {
257 5396 : nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(scr);
258 :
259 2698 : if (classInfo) {
260 2686 : nsresult rv = classInfo->GetFlags(&flags);
261 2686 : if (NS_FAILED(rv))
262 0 : return Throw(rv, ccx);
263 : }
264 : }
265 :
266 2768 : bool overwriteToString = !(flags & nsIClassInfo::DOM_OBJECT)
267 2768 : || Preferences::GetBool("dom.XPCToStringForDOMClasses", false);
268 :
269 8304 : if(id == xpccx->GetStringID(XPCJSContext::IDX_TO_STRING)
270 8304 : && overwriteToString)
271 : {
272 0 : call = XPC_WN_Shared_ToString;
273 0 : name = xpccx->GetStringName(XPCJSContext::IDX_TO_STRING);
274 2768 : } else if (id == xpccx->GetStringID(XPCJSContext::IDX_TO_SOURCE)) {
275 0 : call = XPC_WN_Shared_ToSource;
276 0 : name = xpccx->GetStringName(XPCJSContext::IDX_TO_SOURCE);
277 2768 : } else if (id == SYMBOL_TO_JSID(
278 2768 : JS::GetWellKnownSymbol(ccx, JS::SymbolCode::toPrimitive)))
279 : {
280 65 : call = XPC_WN_Shared_toPrimitive;
281 65 : name = "[Symbol.toPrimitive]";
282 : } else {
283 2703 : call = nullptr;
284 : }
285 :
286 2768 : if (call) {
287 130 : RootedFunction fun(ccx, JS_NewFunction(ccx, call, 0, 0, name));
288 65 : if (!fun) {
289 0 : JS_ReportOutOfMemory(ccx);
290 0 : return false;
291 : }
292 :
293 130 : AutoResolveName arn(ccx, id);
294 65 : if (resolved)
295 65 : *resolved = true;
296 130 : RootedObject value(ccx, JS_GetFunctionObject(fun));
297 130 : return JS_DefinePropertyById(ccx, obj, id, value,
298 65 : propFlags & ~JSPROP_ENUMERATE);
299 : }
300 : }
301 : // This *might* be a tearoff name that is not yet part of our
302 : // set. Let's lookup the name and see if it is the name of an
303 : // interface. Then we'll see if the object actually *does* this
304 : // interface and add a tearoff as necessary.
305 :
306 2703 : if (wrapperToReflectInterfaceNames) {
307 6 : JSAutoByteString name;
308 6 : RefPtr<XPCNativeInterface> iface2;
309 : XPCWrappedNativeTearOff* to;
310 6 : RootedObject jso(ccx);
311 3 : nsresult rv = NS_OK;
312 :
313 12 : if (JSID_IS_STRING(id) &&
314 9 : name.encodeLatin1(ccx, JSID_TO_STRING(id)) &&
315 12 : (iface2 = XPCNativeInterface::GetNewOrUsed(name.ptr())) &&
316 : nullptr != (to = wrapperToReflectInterfaceNames->
317 6 : FindTearOff(iface2, true, &rv)) &&
318 3 : nullptr != (jso = to->GetJSObject()))
319 :
320 : {
321 0 : AutoResolveName arn(ccx, id);
322 0 : if (resolved)
323 0 : *resolved = true;
324 0 : return JS_DefinePropertyById(ccx, obj, id, jso,
325 0 : propFlags & ~JSPROP_ENUMERATE);
326 3 : } else if (NS_FAILED(rv) && rv != NS_ERROR_NO_INTERFACE) {
327 0 : return Throw(rv, ccx);
328 : }
329 : }
330 :
331 : // This *might* be a double wrapped JSObject
332 8112 : if (wrapperToReflectDoubleWrap &&
333 5415 : id == xpccx->GetStringID(XPCJSContext::IDX_WRAPPED_JSOBJECT) &&
334 3 : GetDoubleWrappedJSObject(ccx, wrapperToReflectDoubleWrap)) {
335 : // We build and add a getter function.
336 : // A security check is done on a per-get basis.
337 :
338 : JSFunction* fun;
339 :
340 3 : id = xpccx->GetStringID(XPCJSContext::IDX_WRAPPED_JSOBJECT);
341 3 : name = xpccx->GetStringName(XPCJSContext::IDX_WRAPPED_JSOBJECT);
342 :
343 3 : fun = JS_NewFunction(ccx, XPC_WN_DoubleWrappedGetter,
344 3 : 0, 0, name);
345 :
346 3 : if (!fun)
347 0 : return false;
348 :
349 6 : RootedObject funobj(ccx, JS_GetFunctionObject(fun));
350 3 : if (!funobj)
351 0 : return false;
352 :
353 3 : propFlags |= JSPROP_GETTER | JSPROP_SHARED;
354 3 : propFlags &= ~JSPROP_ENUMERATE;
355 :
356 6 : AutoResolveName arn(ccx, id);
357 3 : if (resolved)
358 3 : *resolved = true;
359 6 : return JS_DefinePropertyById(ccx, obj, id, UndefinedHandleValue, propFlags,
360 3 : JS_DATA_TO_FUNC_PTR(JSNative, funobj.get()),
361 3 : nullptr);
362 : }
363 :
364 2700 : if (resolved)
365 2700 : *resolved = false;
366 2700 : return true;
367 : }
368 :
369 2808 : if (!member) {
370 0 : if (wrapperToReflectInterfaceNames) {
371 : XPCWrappedNativeTearOff* to =
372 0 : wrapperToReflectInterfaceNames->FindTearOff(iface, true);
373 :
374 0 : if (!to)
375 0 : return false;
376 0 : RootedObject jso(ccx, to->GetJSObject());
377 0 : if (!jso)
378 0 : return false;
379 :
380 0 : AutoResolveName arn(ccx, id);
381 0 : if (resolved)
382 0 : *resolved = true;
383 0 : return JS_DefinePropertyById(ccx, obj, id, jso,
384 0 : propFlags & ~JSPROP_ENUMERATE);
385 : }
386 0 : if (resolved)
387 0 : *resolved = false;
388 0 : return true;
389 : }
390 :
391 2808 : if (member->IsConstant()) {
392 106 : RootedValue val(ccx);
393 106 : AutoResolveName arn(ccx, id);
394 53 : if (resolved)
395 53 : *resolved = true;
396 212 : return member->GetConstantValue(ccx, iface, val.address()) &&
397 212 : JS_DefinePropertyById(ccx, obj, id, val, propFlags);
398 : }
399 :
400 2755 : if (scope->HasInterposition()) {
401 0 : Rooted<PropertyDescriptor> desc(ccx);
402 0 : if (!xpc::InterposeProperty(ccx, obj, iface->GetIID(), id, &desc))
403 0 : return false;
404 :
405 0 : if (desc.object()) {
406 0 : AutoResolveName arn(ccx, id);
407 0 : if (resolved)
408 0 : *resolved = true;
409 0 : desc.attributesRef() |= JSPROP_RESOLVING;
410 0 : return JS_DefinePropertyById(ccx, obj, id, desc);
411 : }
412 : }
413 :
414 16514 : if (id == xpccx->GetStringID(XPCJSContext::IDX_TO_STRING) ||
415 16525 : id == xpccx->GetStringID(XPCJSContext::IDX_TO_SOURCE) ||
416 1330 : (scr &&
417 1480 : scr->DontEnumQueryInterface() &&
418 2905 : id == xpccx->GetStringID(XPCJSContext::IDX_QUERY_INTERFACE)))
419 11 : propFlags &= ~JSPROP_ENUMERATE;
420 :
421 5510 : RootedValue funval(ccx);
422 2755 : if (!member->NewFunctionObject(ccx, iface, obj, funval.address()))
423 0 : return false;
424 :
425 2755 : if (member->IsMethod()) {
426 2758 : AutoResolveName arn(ccx, id);
427 1379 : if (resolved)
428 1379 : *resolved = true;
429 1379 : return JS_DefinePropertyById(ccx, obj, id, funval, propFlags);
430 : }
431 :
432 : // else...
433 :
434 1376 : MOZ_ASSERT(member->IsAttribute(), "way broken!");
435 :
436 1376 : propFlags |= JSPROP_GETTER | JSPROP_SHARED;
437 1376 : propFlags &= ~JSPROP_READONLY;
438 1376 : JSObject* funobj = funval.toObjectOrNull();
439 1376 : JSNative getter = JS_DATA_TO_FUNC_PTR(JSNative, funobj);
440 : JSNative setter;
441 1376 : if (member->IsWritableAttribute()) {
442 216 : propFlags |= JSPROP_SETTER;
443 216 : setter = JS_DATA_TO_FUNC_PTR(JSNative, funobj);
444 : } else {
445 1160 : setter = nullptr;
446 : }
447 :
448 2752 : AutoResolveName arn(ccx, id);
449 1376 : if (resolved)
450 1376 : *resolved = true;
451 :
452 1376 : return JS_DefinePropertyById(ccx, obj, id, UndefinedHandleValue, propFlags, getter, setter);
453 : }
454 :
455 : /***************************************************************************/
456 : /***************************************************************************/
457 :
458 : static bool
459 1387 : XPC_WN_OnlyIWrite_AddPropertyStub(JSContext* cx, HandleObject obj, HandleId id, HandleValue v)
460 : {
461 2774 : XPCCallContext ccx(cx, obj, nullptr, id);
462 1387 : XPCWrappedNative* wrapper = ccx.GetWrapper();
463 1387 : THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
464 :
465 : // Allow only XPConnect to add/set the property
466 1387 : if (ccx.GetResolveName() == id)
467 1387 : return true;
468 :
469 0 : return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
470 : }
471 :
472 : bool
473 0 : XPC_WN_CannotModifyPropertyStub(JSContext* cx, HandleObject obj, HandleId id,
474 : HandleValue v)
475 : {
476 0 : return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
477 : }
478 :
479 : bool
480 0 : XPC_WN_CannotDeletePropertyStub(JSContext* cx, HandleObject obj, HandleId id,
481 : ObjectOpResult& result)
482 : {
483 0 : return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
484 : }
485 :
486 : bool
487 0 : XPC_WN_CannotModifySetPropertyStub(JSContext* cx, HandleObject obj, HandleId id,
488 : MutableHandleValue vp, ObjectOpResult& result)
489 : {
490 0 : return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
491 : }
492 :
493 : bool
494 6 : XPC_WN_Shared_Enumerate(JSContext* cx, HandleObject obj)
495 : {
496 12 : XPCCallContext ccx(cx, obj);
497 6 : XPCWrappedNative* wrapper = ccx.GetWrapper();
498 6 : THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
499 :
500 : // Since we aren't going to enumerate tearoff names and the prototype
501 : // handles non-mutated members, we can do this potential short-circuit.
502 6 : if (!wrapper->HasMutatedSet())
503 4 : return true;
504 :
505 2 : XPCNativeSet* set = wrapper->GetSet();
506 4 : XPCNativeSet* protoSet = wrapper->HasProto() ?
507 4 : wrapper->GetProto()->GetSet() : nullptr;
508 :
509 2 : uint16_t interface_count = set->GetInterfaceCount();
510 2 : XPCNativeInterface** interfaceArray = set->GetInterfaceArray();
511 10 : for (uint16_t i = 0; i < interface_count; i++) {
512 8 : XPCNativeInterface* iface = interfaceArray[i];
513 8 : uint16_t member_count = iface->GetMemberCount();
514 98 : for (uint16_t k = 0; k < member_count; k++) {
515 90 : XPCNativeMember* member = iface->GetMemberAt(k);
516 90 : jsid name = member->GetName();
517 :
518 : // Skip if this member is going to come from the proto.
519 : uint16_t index;
520 180 : if (protoSet &&
521 174 : protoSet->FindMember(name, nullptr, &index) && index == i)
522 78 : continue;
523 12 : if (!xpc_ForcePropertyResolve(cx, obj, name))
524 0 : return false;
525 : }
526 : }
527 2 : return true;
528 : }
529 :
530 : /***************************************************************************/
531 :
532 : enum WNHelperType {
533 : WN_NOHELPER,
534 : WN_HELPER
535 : };
536 :
537 : static void
538 0 : WrappedNativeFinalize(js::FreeOp* fop, JSObject* obj, WNHelperType helperType)
539 : {
540 0 : const js::Class* clazz = js::GetObjectClass(obj);
541 0 : if (clazz->flags & JSCLASS_DOM_GLOBAL) {
542 0 : mozilla::dom::DestroyProtoAndIfaceCache(obj);
543 : }
544 0 : nsISupports* p = static_cast<nsISupports*>(xpc_GetJSPrivate(obj));
545 0 : if (!p)
546 0 : return;
547 :
548 0 : XPCWrappedNative* wrapper = static_cast<XPCWrappedNative*>(p);
549 0 : if (helperType == WN_HELPER)
550 0 : wrapper->GetScriptable()->Finalize(wrapper, js::CastToJSFreeOp(fop), obj);
551 0 : wrapper->FlatJSObjectFinalized();
552 : }
553 :
554 : static void
555 0 : WrappedNativeObjectMoved(JSObject* obj, const JSObject* old)
556 : {
557 0 : nsISupports* p = static_cast<nsISupports*>(xpc_GetJSPrivate(obj));
558 0 : if (!p)
559 0 : return;
560 :
561 0 : XPCWrappedNative* wrapper = static_cast<XPCWrappedNative*>(p);
562 0 : wrapper->FlatJSObjectMoved(obj, old);
563 : }
564 :
565 : void
566 0 : XPC_WN_NoHelper_Finalize(js::FreeOp* fop, JSObject* obj)
567 : {
568 0 : WrappedNativeFinalize(fop, obj, WN_NOHELPER);
569 0 : }
570 :
571 : /*
572 : * General comment about XPConnect tracing: Given a C++ object |wrapper| and its
573 : * corresponding JS object |obj|, calling |wrapper->TraceSelf| will ask the JS
574 : * engine to mark |obj|. Eventually, this will lead to the trace hook being
575 : * called for |obj|. The trace hook should call |wrapper->TraceInside|, which
576 : * should mark any JS objects held by |wrapper| as members.
577 : */
578 :
579 : /* static */ void
580 183 : XPCWrappedNative::Trace(JSTracer* trc, JSObject* obj)
581 : {
582 183 : const js::Class* clazz = js::GetObjectClass(obj);
583 183 : if (clazz->flags & JSCLASS_DOM_GLOBAL) {
584 0 : mozilla::dom::TraceProtoAndIfaceCache(trc, obj);
585 : }
586 183 : MOZ_ASSERT(IS_WN_CLASS(clazz));
587 :
588 183 : XPCWrappedNative* wrapper = XPCWrappedNative::Get(obj);
589 183 : if (wrapper && wrapper->IsValid())
590 183 : wrapper->TraceInside(trc);
591 183 : }
592 :
593 : void
594 177 : XPCWrappedNative_Trace(JSTracer* trc, JSObject* obj)
595 : {
596 177 : XPCWrappedNative::Trace(trc, obj);
597 177 : }
598 :
599 : static bool
600 2528 : XPC_WN_NoHelper_Resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
601 : {
602 5056 : XPCCallContext ccx(cx, obj, nullptr, id);
603 2528 : XPCWrappedNative* wrapper = ccx.GetWrapper();
604 2528 : THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
605 :
606 2528 : XPCNativeSet* set = ccx.GetSet();
607 2528 : if (!set)
608 0 : return true;
609 :
610 : // Don't resolve properties that are on our prototype.
611 2528 : if (ccx.GetInterface() && !ccx.GetStaticMemberIsLocal())
612 1141 : return true;
613 :
614 1387 : return DefinePropertyIfFound(ccx, obj, id,
615 : set, nullptr, nullptr, wrapper->GetScope(),
616 : true, wrapper, wrapper, nullptr,
617 : JSPROP_ENUMERATE |
618 : JSPROP_READONLY |
619 : JSPROP_PERMANENT,
620 1387 : resolvedp);
621 : }
622 :
623 : static const js::ClassOps XPC_WN_NoHelper_JSClassOps = {
624 : XPC_WN_OnlyIWrite_AddPropertyStub, // addProperty
625 : XPC_WN_CannotDeletePropertyStub, // delProperty
626 : nullptr, // getProperty
627 : nullptr, // setProperty
628 : XPC_WN_Shared_Enumerate, // enumerate
629 : nullptr, // newEnumerate
630 : XPC_WN_NoHelper_Resolve, // resolve
631 : nullptr, // mayResolve
632 : XPC_WN_NoHelper_Finalize, // finalize
633 : nullptr, // call
634 : nullptr, // construct
635 : nullptr, // hasInstance
636 : XPCWrappedNative::Trace, // trace
637 : };
638 :
639 : const js::ClassExtension XPC_WN_JSClassExtension = {
640 : nullptr, // weakmapKeyDelegateOp
641 : WrappedNativeObjectMoved
642 : };
643 :
644 : const js::Class XPC_WN_NoHelper_JSClass = {
645 : "XPCWrappedNative_NoHelper",
646 : XPC_WRAPPER_FLAGS |
647 : JSCLASS_IS_WRAPPED_NATIVE |
648 : JSCLASS_PRIVATE_IS_NSISUPPORTS |
649 : JSCLASS_FOREGROUND_FINALIZE,
650 : &XPC_WN_NoHelper_JSClassOps,
651 : JS_NULL_CLASS_SPEC,
652 : &XPC_WN_JSClassExtension,
653 : JS_NULL_OBJECT_OPS
654 : };
655 :
656 :
657 : /***************************************************************************/
658 :
659 : bool
660 1408 : XPC_WN_MaybeResolvingPropertyStub(JSContext* cx, HandleObject obj, HandleId id, HandleValue v)
661 : {
662 2816 : XPCCallContext ccx(cx, obj);
663 1408 : XPCWrappedNative* wrapper = ccx.GetWrapper();
664 1408 : THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
665 :
666 1408 : if (ccx.GetResolvingWrapper() == wrapper)
667 1408 : return true;
668 0 : return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
669 : }
670 :
671 : bool
672 0 : XPC_WN_MaybeResolvingSetPropertyStub(JSContext* cx, HandleObject obj, HandleId id,
673 : MutableHandleValue vp, ObjectOpResult& result)
674 : {
675 0 : result.succeed();
676 0 : return XPC_WN_MaybeResolvingPropertyStub(cx, obj, id, vp);
677 : }
678 :
679 : bool
680 0 : XPC_WN_MaybeResolvingDeletePropertyStub(JSContext* cx, HandleObject obj, HandleId id,
681 : ObjectOpResult& result)
682 : {
683 0 : XPCCallContext ccx(cx, obj);
684 0 : XPCWrappedNative* wrapper = ccx.GetWrapper();
685 0 : THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
686 :
687 0 : if (ccx.GetResolvingWrapper() == wrapper) {
688 0 : return result.succeed();
689 : }
690 0 : return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
691 : }
692 :
693 : // macro fun!
694 : #define PRE_HELPER_STUB \
695 : /* It's very important for "unwrapped" to be rooted here. */ \
696 : RootedObject unwrapped(cx, js::CheckedUnwrap(obj, false)); \
697 : if (!unwrapped) { \
698 : JS_ReportErrorASCII(cx, "Permission denied to operate on object."); \
699 : return false; \
700 : } \
701 : if (!IS_WN_REFLECTOR(unwrapped)) { \
702 : return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); \
703 : } \
704 : XPCWrappedNative* wrapper = XPCWrappedNative::Get(unwrapped); \
705 : THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); \
706 : bool retval = true; \
707 : nsresult rv = wrapper->GetScriptable()->
708 :
709 : #define POST_HELPER_STUB \
710 : if (NS_FAILED(rv)) \
711 : return Throw(rv, cx); \
712 : return retval;
713 :
714 : #define POST_HELPER_STUB_WITH_OBJECTOPRESULT(failMethod) \
715 : if (NS_FAILED(rv)) \
716 : return Throw(rv, cx); \
717 : return retval ? result.succeed() : result.failMethod();
718 :
719 : bool
720 6 : XPC_WN_Helper_GetProperty(JSContext* cx, HandleObject obj, HandleId id,
721 : MutableHandleValue vp)
722 : {
723 12 : PRE_HELPER_STUB
724 6 : GetProperty(wrapper, cx, obj, id, vp.address(), &retval);
725 6 : POST_HELPER_STUB
726 : }
727 :
728 : bool
729 6 : XPC_WN_Helper_SetProperty(JSContext* cx, HandleObject obj, HandleId id,
730 : MutableHandleValue vp, ObjectOpResult& result)
731 : {
732 12 : PRE_HELPER_STUB
733 6 : SetProperty(wrapper, cx, obj, id, vp.address(), &retval);
734 6 : POST_HELPER_STUB_WITH_OBJECTOPRESULT(failReadOnly)
735 : }
736 :
737 : bool
738 93 : XPC_WN_Helper_Call(JSContext* cx, unsigned argc, Value* vp)
739 : {
740 93 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
741 : // N.B. we want obj to be the callee, not JS_THIS(cx, vp)
742 186 : RootedObject obj(cx, &args.callee());
743 :
744 : XPCCallContext ccx(cx, obj, nullptr, JSID_VOIDHANDLE, args.length(),
745 186 : args.array(), args.rval().address());
746 93 : if (!ccx.IsValid())
747 0 : return false;
748 :
749 186 : PRE_HELPER_STUB
750 93 : Call(wrapper, cx, obj, args, &retval);
751 93 : POST_HELPER_STUB
752 : }
753 :
754 : bool
755 41 : XPC_WN_Helper_Construct(JSContext* cx, unsigned argc, Value* vp)
756 : {
757 41 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
758 82 : RootedObject obj(cx, &args.callee());
759 41 : if (!obj)
760 0 : return false;
761 :
762 : XPCCallContext ccx(cx, obj, nullptr, JSID_VOIDHANDLE, args.length(),
763 82 : args.array(), args.rval().address());
764 41 : if (!ccx.IsValid())
765 0 : return false;
766 :
767 82 : PRE_HELPER_STUB
768 41 : Construct(wrapper, cx, obj, args, &retval);
769 41 : POST_HELPER_STUB
770 : }
771 :
772 : bool
773 163 : XPC_WN_Helper_HasInstance(JSContext* cx, HandleObject obj, MutableHandleValue valp, bool* bp)
774 : {
775 : bool retval2;
776 326 : PRE_HELPER_STUB
777 163 : HasInstance(wrapper, cx, obj, valp, &retval2, &retval);
778 163 : *bp = retval2;
779 163 : POST_HELPER_STUB
780 : }
781 :
782 : void
783 0 : XPC_WN_Helper_Finalize(js::FreeOp* fop, JSObject* obj)
784 : {
785 0 : WrappedNativeFinalize(fop, obj, WN_HELPER);
786 0 : }
787 :
788 : bool
789 19330 : XPC_WN_Helper_Resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
790 : {
791 19330 : nsresult rv = NS_OK;
792 19330 : bool retval = true;
793 19330 : bool resolved = false;
794 38660 : XPCCallContext ccx(cx, obj);
795 19330 : XPCWrappedNative* wrapper = ccx.GetWrapper();
796 19330 : THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
797 :
798 38660 : RootedId old(cx, ccx.SetResolveName(id));
799 :
800 38660 : nsCOMPtr<nsIXPCScriptable> scr = wrapper->GetScriptable();
801 19330 : if (scr && scr->WantResolve()) {
802 : XPCWrappedNative* oldResolvingWrapper;
803 17213 : bool allowPropMods = scr->AllowPropModsDuringResolve();
804 :
805 17213 : if (allowPropMods)
806 2771 : oldResolvingWrapper = ccx.SetResolvingWrapper(wrapper);
807 :
808 17213 : rv = scr->Resolve(wrapper, cx, obj, id, &resolved, &retval);
809 :
810 17213 : if (allowPropMods)
811 2771 : (void)ccx.SetResolvingWrapper(oldResolvingWrapper);
812 : }
813 :
814 19330 : old = ccx.SetResolveName(old);
815 19330 : MOZ_ASSERT(old == id, "bad nest");
816 :
817 19330 : if (NS_FAILED(rv)) {
818 0 : return Throw(rv, cx);
819 : }
820 :
821 19330 : if (resolved) {
822 1371 : *resolvedp = true;
823 17959 : } else if (wrapper->HasMutatedSet()) {
824 : // We are here if scriptable did not resolve this property and
825 : // it *might* be in the instance set but not the proto set.
826 :
827 298 : XPCNativeSet* set = wrapper->GetSet();
828 298 : XPCNativeSet* protoSet = wrapper->HasProto() ?
829 298 : wrapper->GetProto()->GetSet() : nullptr;
830 298 : XPCNativeMember* member = nullptr;
831 596 : RefPtr<XPCNativeInterface> iface;
832 298 : bool IsLocal = false;
833 :
834 298 : if (set->FindMember(id, &member, &iface, protoSet, &IsLocal) &&
835 : IsLocal) {
836 :
837 : XPCWrappedNative* wrapperForInterfaceNames =
838 298 : (scr && scr->DontReflectInterfaceNames()) ? nullptr : wrapper;
839 :
840 : XPCWrappedNative* oldResolvingWrapper =
841 298 : ccx.SetResolvingWrapper(wrapper);
842 298 : retval = DefinePropertyIfFound(ccx, obj, id,
843 : set, iface, member,
844 : wrapper->GetScope(),
845 : false,
846 : wrapperForInterfaceNames,
847 : nullptr, scr,
848 : JSPROP_ENUMERATE, resolvedp);
849 298 : (void)ccx.SetResolvingWrapper(oldResolvingWrapper);
850 : }
851 : }
852 :
853 19330 : return retval;
854 : }
855 :
856 : bool
857 1 : XPC_WN_Helper_Enumerate(JSContext* cx, HandleObject obj)
858 : {
859 2 : XPCCallContext ccx(cx, obj);
860 1 : XPCWrappedNative* wrapper = ccx.GetWrapper();
861 1 : THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
862 :
863 2 : nsCOMPtr<nsIXPCScriptable> scr = wrapper->GetScriptable();
864 1 : if (!scr || !scr->WantEnumerate())
865 0 : return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
866 :
867 1 : if (!XPC_WN_Shared_Enumerate(cx, obj))
868 0 : return false;
869 :
870 1 : bool retval = true;
871 1 : nsresult rv = scr->Enumerate(wrapper, cx, obj, &retval);
872 1 : if (NS_FAILED(rv))
873 0 : return Throw(rv, cx);
874 1 : return retval;
875 : }
876 :
877 : /***************************************************************************/
878 :
879 : bool
880 3 : XPC_WN_NewEnumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
881 : bool enumerableOnly)
882 : {
883 6 : XPCCallContext ccx(cx, obj);
884 3 : XPCWrappedNative* wrapper = ccx.GetWrapper();
885 3 : THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
886 :
887 6 : nsCOMPtr<nsIXPCScriptable> scr = wrapper->GetScriptable();
888 3 : if (!scr || !scr->WantNewEnumerate())
889 0 : return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
890 :
891 3 : if (!XPC_WN_Shared_Enumerate(cx, obj))
892 0 : return false;
893 :
894 3 : bool retval = true;
895 3 : nsresult rv = scr->NewEnumerate(wrapper, cx, obj, properties, &retval);
896 3 : if (NS_FAILED(rv))
897 0 : return Throw(rv, cx);
898 3 : return retval;
899 : }
900 :
901 : /***************************************************************************/
902 : /***************************************************************************/
903 :
904 : // Compatibility hack.
905 : //
906 : // XPConnect used to do all sorts of funny tricks to find the "correct"
907 : // |this| object for a given method (often to the detriment of proper
908 : // call/apply). When these tricks were removed, a fair amount of chrome
909 : // code broke, because it was relying on being able to grab methods off
910 : // some XPCOM object (like the nsITelemetry service) and invoke them without
911 : // a proper |this|. So, if it's quite clear that we're in this situation and
912 : // about to use a |this| argument that just won't work, fix things up.
913 : //
914 : // This hack is only useful for getters/setters if someone sets an XPCOM object
915 : // as the prototype for a vanilla JS object and expects the XPCOM attributes to
916 : // work on the derived object, which we really don't want to support. But we
917 : // handle it anyway, for now, to minimize regression risk on an already-risky
918 : // landing.
919 : //
920 : // This hack is mainly useful for the NoHelper JSClass. We also fix up
921 : // Components.utils because it implements nsIXPCScriptable (giving it a custom
922 : // JSClass) but not nsIClassInfo (which would put the methods on a prototype).
923 :
924 : #define IS_NOHELPER_CLASS(clasp) (clasp == &XPC_WN_NoHelper_JSClass)
925 : #define IS_CU_CLASS(clasp) (clasp->name[0] == 'n' && !strcmp(clasp->name, "nsXPCComponents_Utils"))
926 :
927 : MOZ_ALWAYS_INLINE JSObject*
928 11152 : FixUpThisIfBroken(JSObject* obj, JSObject* funobj)
929 : {
930 11152 : if (funobj) {
931 : JSObject* parentObj =
932 : &js::GetFunctionNativeReserved(funobj,
933 11152 : XPC_FUNCTION_PARENT_OBJECT_SLOT).toObject();
934 11152 : const js::Class* parentClass = js::GetObjectClass(parentObj);
935 11152 : if (MOZ_UNLIKELY((IS_NOHELPER_CLASS(parentClass) || IS_CU_CLASS(parentClass)) &&
936 : (js::GetObjectClass(obj) != parentClass)))
937 : {
938 20 : return parentObj;
939 : }
940 : }
941 11132 : return obj;
942 : }
943 :
944 : bool
945 8249 : XPC_WN_CallMethod(JSContext* cx, unsigned argc, Value* vp)
946 : {
947 8249 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
948 8249 : MOZ_ASSERT(JS_TypeOfValue(cx, args.calleev()) == JSTYPE_FUNCTION, "bad function");
949 16497 : RootedObject funobj(cx, &args.callee());
950 :
951 16497 : RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
952 8249 : if (!obj)
953 0 : return false;
954 :
955 8249 : obj = FixUpThisIfBroken(obj, funobj);
956 : XPCCallContext ccx(cx, obj, funobj, JSID_VOIDHANDLE, args.length(),
957 16497 : args.array(), vp);
958 8249 : XPCWrappedNative* wrapper = ccx.GetWrapper();
959 8249 : THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
960 :
961 16497 : RefPtr<XPCNativeInterface> iface;
962 : XPCNativeMember* member;
963 :
964 8249 : if (!XPCNativeMember::GetCallInfo(funobj, &iface, &member))
965 0 : return Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, cx);
966 8249 : ccx.SetCallInfo(iface, member, false);
967 8249 : return XPCWrappedNative::CallMethod(ccx);
968 : }
969 :
970 : bool
971 2903 : XPC_WN_GetterSetter(JSContext* cx, unsigned argc, Value* vp)
972 : {
973 2903 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
974 2903 : MOZ_ASSERT(JS_TypeOfValue(cx, args.calleev()) == JSTYPE_FUNCTION, "bad function");
975 5806 : RootedObject funobj(cx, &args.callee());
976 :
977 5806 : RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
978 2903 : if (!obj)
979 0 : return false;
980 :
981 2903 : obj = FixUpThisIfBroken(obj, funobj);
982 : XPCCallContext ccx(cx, obj, funobj, JSID_VOIDHANDLE, args.length(),
983 5806 : args.array(), vp);
984 2903 : XPCWrappedNative* wrapper = ccx.GetWrapper();
985 2903 : THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
986 :
987 5806 : RefPtr<XPCNativeInterface> iface;
988 : XPCNativeMember* member;
989 :
990 2903 : if (!XPCNativeMember::GetCallInfo(funobj, &iface, &member))
991 0 : return Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, cx);
992 :
993 2903 : if (args.length() != 0 && member->IsWritableAttribute()) {
994 38 : ccx.SetCallInfo(iface, member, true);
995 38 : bool retval = XPCWrappedNative::SetAttribute(ccx);
996 38 : if (retval)
997 38 : args.rval().set(args[0]);
998 38 : return retval;
999 : }
1000 : // else...
1001 :
1002 2865 : ccx.SetCallInfo(iface, member, false);
1003 2865 : return XPCWrappedNative::GetAttribute(ccx);
1004 : }
1005 :
1006 : /***************************************************************************/
1007 :
1008 : static bool
1009 1 : XPC_WN_Shared_Proto_Enumerate(JSContext* cx, HandleObject obj)
1010 : {
1011 1 : MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_Proto_JSClass ||
1012 : js::GetObjectClass(obj) == &XPC_WN_NoMods_Proto_JSClass,
1013 : "bad proto");
1014 : XPCWrappedNativeProto* self =
1015 1 : (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
1016 1 : if (!self)
1017 0 : return false;
1018 :
1019 1 : XPCNativeSet* set = self->GetSet();
1020 1 : if (!set)
1021 0 : return false;
1022 :
1023 2 : XPCCallContext ccx(cx);
1024 1 : if (!ccx.IsValid())
1025 0 : return false;
1026 :
1027 1 : uint16_t interface_count = set->GetInterfaceCount();
1028 1 : XPCNativeInterface** interfaceArray = set->GetInterfaceArray();
1029 4 : for (uint16_t i = 0; i < interface_count; i++) {
1030 3 : XPCNativeInterface* iface = interfaceArray[i];
1031 3 : uint16_t member_count = iface->GetMemberCount();
1032 :
1033 16 : for (uint16_t k = 0; k < member_count; k++) {
1034 13 : if (!xpc_ForcePropertyResolve(cx, obj, iface->GetMemberAt(k)->GetName()))
1035 0 : return false;
1036 : }
1037 : }
1038 :
1039 1 : return true;
1040 : }
1041 :
1042 : static void
1043 0 : XPC_WN_Shared_Proto_Finalize(js::FreeOp* fop, JSObject* obj)
1044 : {
1045 : // This can be null if xpc shutdown has already happened
1046 0 : XPCWrappedNativeProto* p = (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
1047 0 : if (p)
1048 0 : p->JSProtoObjectFinalized(fop, obj);
1049 0 : }
1050 :
1051 : static void
1052 0 : XPC_WN_Shared_Proto_ObjectMoved(JSObject* obj, const JSObject* old)
1053 : {
1054 : // This can be null if xpc shutdown has already happened
1055 0 : XPCWrappedNativeProto* p = (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
1056 0 : if (p)
1057 0 : p->JSProtoObjectMoved(obj, old);
1058 0 : }
1059 :
1060 : static void
1061 24 : XPC_WN_Shared_Proto_Trace(JSTracer* trc, JSObject* obj)
1062 : {
1063 : // This can be null if xpc shutdown has already happened
1064 : XPCWrappedNativeProto* p =
1065 24 : (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
1066 24 : if (p)
1067 24 : p->TraceInside(trc);
1068 24 : }
1069 :
1070 : /*****************************************************/
1071 :
1072 : static bool
1073 121 : XPC_WN_ModsAllowed_Proto_Resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvep)
1074 : {
1075 121 : MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_Proto_JSClass,
1076 : "bad proto");
1077 :
1078 : XPCWrappedNativeProto* self =
1079 121 : (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
1080 121 : if (!self)
1081 0 : return false;
1082 :
1083 242 : XPCCallContext ccx(cx);
1084 121 : if (!ccx.IsValid())
1085 0 : return false;
1086 :
1087 242 : nsCOMPtr<nsIXPCScriptable> scr = self->GetScriptable();
1088 121 : return DefinePropertyIfFound(ccx, obj, id,
1089 : self->GetSet(), nullptr, nullptr,
1090 : self->GetScope(),
1091 : true, nullptr, nullptr, scr,
1092 121 : JSPROP_ENUMERATE, resolvep);
1093 : }
1094 :
1095 : static const js::ClassOps XPC_WN_ModsAllowed_Proto_JSClassOps = {
1096 : nullptr, // addProperty
1097 : nullptr, // delProperty
1098 : nullptr, // getProperty
1099 : nullptr, // setProperty
1100 : XPC_WN_Shared_Proto_Enumerate, // enumerate
1101 : nullptr, // newEnumerate
1102 : XPC_WN_ModsAllowed_Proto_Resolve, // resolve
1103 : nullptr, // mayResolve
1104 : XPC_WN_Shared_Proto_Finalize, // finalize
1105 : nullptr, // call
1106 : nullptr, // construct
1107 : nullptr, // hasInstance
1108 : XPC_WN_Shared_Proto_Trace, // trace
1109 : };
1110 :
1111 : static const js::ClassExtension XPC_WN_Shared_Proto_ClassExtension = {
1112 : nullptr, /* weakmapKeyDelegateOp */
1113 : XPC_WN_Shared_Proto_ObjectMoved
1114 : };
1115 :
1116 : const js::Class XPC_WN_ModsAllowed_Proto_JSClass = {
1117 : "XPC_WN_ModsAllowed_Proto_JSClass",
1118 : XPC_WRAPPER_FLAGS,
1119 : &XPC_WN_ModsAllowed_Proto_JSClassOps,
1120 : JS_NULL_CLASS_SPEC,
1121 : &XPC_WN_Shared_Proto_ClassExtension,
1122 : JS_NULL_OBJECT_OPS
1123 : };
1124 :
1125 : /***************************************************************************/
1126 :
1127 : static bool
1128 1118 : XPC_WN_OnlyIWrite_Proto_AddPropertyStub(JSContext* cx, HandleObject obj, HandleId id,
1129 : HandleValue v)
1130 : {
1131 1118 : MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_NoMods_Proto_JSClass,
1132 : "bad proto");
1133 :
1134 : XPCWrappedNativeProto* self =
1135 1118 : (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
1136 1118 : if (!self)
1137 0 : return false;
1138 :
1139 2236 : XPCCallContext ccx(cx);
1140 1118 : if (!ccx.IsValid())
1141 0 : return false;
1142 :
1143 : // Allow XPConnect to add the property only
1144 1118 : if (ccx.GetResolveName() == id)
1145 1118 : return true;
1146 :
1147 0 : return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
1148 : }
1149 :
1150 : static bool
1151 3770 : XPC_WN_NoMods_Proto_Resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
1152 : {
1153 3770 : MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_NoMods_Proto_JSClass,
1154 : "bad proto");
1155 :
1156 : XPCWrappedNativeProto* self =
1157 3770 : (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
1158 3770 : if (!self)
1159 0 : return false;
1160 :
1161 7540 : XPCCallContext ccx(cx);
1162 3770 : if (!ccx.IsValid())
1163 0 : return false;
1164 :
1165 7540 : nsCOMPtr<nsIXPCScriptable> scr = self->GetScriptable();
1166 :
1167 3770 : return DefinePropertyIfFound(ccx, obj, id,
1168 : self->GetSet(), nullptr, nullptr,
1169 : self->GetScope(),
1170 : true, nullptr, nullptr, scr,
1171 : JSPROP_READONLY |
1172 : JSPROP_PERMANENT |
1173 3770 : JSPROP_ENUMERATE, resolvedp);
1174 : }
1175 :
1176 : static const js::ClassOps XPC_WN_NoMods_Proto_JSClassOps = {
1177 : XPC_WN_OnlyIWrite_Proto_AddPropertyStub, // addProperty
1178 : XPC_WN_CannotDeletePropertyStub, // delProperty
1179 : nullptr, // getProperty
1180 : nullptr, // setProperty
1181 : XPC_WN_Shared_Proto_Enumerate, // enumerate
1182 : nullptr, // newEnumerate
1183 : XPC_WN_NoMods_Proto_Resolve, // resolve
1184 : nullptr, // mayResolve
1185 : XPC_WN_Shared_Proto_Finalize, // finalize
1186 : nullptr, // call
1187 : nullptr, // construct
1188 : nullptr, // hasInstance
1189 : XPC_WN_Shared_Proto_Trace, // trace
1190 : };
1191 :
1192 : const js::Class XPC_WN_NoMods_Proto_JSClass = {
1193 : "XPC_WN_NoMods_Proto_JSClass",
1194 : XPC_WRAPPER_FLAGS,
1195 : &XPC_WN_NoMods_Proto_JSClassOps,
1196 : JS_NULL_CLASS_SPEC,
1197 : &XPC_WN_Shared_Proto_ClassExtension,
1198 : JS_NULL_OBJECT_OPS
1199 : };
1200 :
1201 : /***************************************************************************/
1202 :
1203 : static bool
1204 0 : XPC_WN_TearOff_Enumerate(JSContext* cx, HandleObject obj)
1205 : {
1206 0 : XPCCallContext ccx(cx, obj);
1207 0 : XPCWrappedNative* wrapper = ccx.GetWrapper();
1208 0 : THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
1209 :
1210 0 : XPCWrappedNativeTearOff* to = ccx.GetTearOff();
1211 : XPCNativeInterface* iface;
1212 :
1213 0 : if (!to || nullptr == (iface = to->GetInterface()))
1214 0 : return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
1215 :
1216 0 : uint16_t member_count = iface->GetMemberCount();
1217 0 : for (uint16_t k = 0; k < member_count; k++) {
1218 0 : if (!xpc_ForcePropertyResolve(cx, obj, iface->GetMemberAt(k)->GetName()))
1219 0 : return false;
1220 : }
1221 :
1222 0 : return true;
1223 : }
1224 :
1225 : static bool
1226 0 : XPC_WN_TearOff_Resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
1227 : {
1228 0 : XPCCallContext ccx(cx, obj);
1229 0 : XPCWrappedNative* wrapper = ccx.GetWrapper();
1230 0 : THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
1231 :
1232 0 : XPCWrappedNativeTearOff* to = ccx.GetTearOff();
1233 : XPCNativeInterface* iface;
1234 :
1235 0 : if (!to || nullptr == (iface = to->GetInterface()))
1236 0 : return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
1237 :
1238 0 : return DefinePropertyIfFound(ccx, obj, id, nullptr, iface, nullptr,
1239 : wrapper->GetScope(),
1240 : true, nullptr, nullptr, nullptr,
1241 : JSPROP_READONLY |
1242 : JSPROP_PERMANENT |
1243 0 : JSPROP_ENUMERATE, resolvedp);
1244 : }
1245 :
1246 : static void
1247 0 : XPC_WN_TearOff_Finalize(js::FreeOp* fop, JSObject* obj)
1248 : {
1249 : XPCWrappedNativeTearOff* p = (XPCWrappedNativeTearOff*)
1250 0 : xpc_GetJSPrivate(obj);
1251 0 : if (!p)
1252 0 : return;
1253 0 : p->JSObjectFinalized();
1254 : }
1255 :
1256 : static void
1257 0 : XPC_WN_TearOff_ObjectMoved(JSObject* obj, const JSObject* old)
1258 : {
1259 : XPCWrappedNativeTearOff* p = (XPCWrappedNativeTearOff*)
1260 0 : xpc_GetJSPrivate(obj);
1261 0 : if (!p)
1262 0 : return;
1263 0 : p->JSObjectMoved(obj, old);
1264 : }
1265 :
1266 : // Make sure XPC_WRAPPER_FLAGS has no reserved slots, so our
1267 : // XPC_WN_TEAROFF_RESERVED_SLOTS value is OK.
1268 :
1269 : static_assert(((XPC_WRAPPER_FLAGS >> JSCLASS_RESERVED_SLOTS_SHIFT) &
1270 : JSCLASS_RESERVED_SLOTS_MASK) == 0,
1271 : "XPC_WRAPPER_FLAGS should not include any reserved slots");
1272 :
1273 : static const js::ClassOps XPC_WN_Tearoff_JSClassOps = {
1274 : XPC_WN_OnlyIWrite_AddPropertyStub, // addProperty
1275 : XPC_WN_CannotDeletePropertyStub, // delProperty
1276 : nullptr, // getProperty
1277 : nullptr, // setProperty
1278 : XPC_WN_TearOff_Enumerate, // enumerate
1279 : nullptr, // newEnumerate
1280 : XPC_WN_TearOff_Resolve, // resolve
1281 : nullptr, // mayResolve
1282 : XPC_WN_TearOff_Finalize, // finalize
1283 : nullptr, // call
1284 : nullptr, // construct
1285 : nullptr, // hasInstance
1286 : nullptr, // trace
1287 : };
1288 :
1289 : static const js::ClassExtension XPC_WN_Tearoff_JSClassExtension = {
1290 : nullptr, // weakmapKeyDelegateOp
1291 : XPC_WN_TearOff_ObjectMoved
1292 : };
1293 :
1294 : const js::Class XPC_WN_Tearoff_JSClass = {
1295 : "WrappedNative_TearOff",
1296 : XPC_WRAPPER_FLAGS |
1297 : JSCLASS_HAS_RESERVED_SLOTS(XPC_WN_TEAROFF_RESERVED_SLOTS),
1298 : &XPC_WN_Tearoff_JSClassOps,
1299 : JS_NULL_CLASS_SPEC,
1300 : &XPC_WN_Tearoff_JSClassExtension
1301 : };
|