Bug 1371259 part 3. Change UnwrapObject<> and the UNWRAP_OBJECT macro to allow passing in mutable object or value handles for the thing being unwrapped, and do so at various callsites. r=peterv

I did audit all UNWRAP_OBJECT callers to make sure that the lifetimes of all the
temporary Rooted or the RefPtrs they unwrap into are long enough.
This commit is contained in:
Boris Zbarsky 2017-07-10 16:05:24 -04:00
Родитель 5fd161c633
Коммит 5c76874a46
23 изменённых файлов: 304 добавлений и 107 удалений

Просмотреть файл

@ -446,10 +446,12 @@ StructuredCloneHolder::WriteFullySerializableObjects(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
JS::Handle<JSObject*> aObj)
{
JS::Rooted<JSObject*> obj(aCx, aObj);
// See if this is a ImageData object.
{
ImageData* imageData = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageData, aObj, imageData))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageData, &obj, imageData))) {
return WriteStructuredCloneImageData(aCx, aWriter, imageData);
}
}
@ -457,7 +459,7 @@ StructuredCloneHolder::WriteFullySerializableObjects(JSContext* aCx,
// Handle URLSearchParams cloning
{
URLSearchParams* usp = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(URLSearchParams, aObj, usp))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(URLSearchParams, &obj, usp))) {
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_URLSEARCHPARAMS, 0) &&
usp->WriteStructuredClone(aWriter);
}
@ -466,7 +468,7 @@ StructuredCloneHolder::WriteFullySerializableObjects(JSContext* aCx,
// Handle Key cloning
{
CryptoKey* key = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(CryptoKey, aObj, key))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(CryptoKey, &obj, key))) {
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_WEBCRYPTO_KEY, 0) &&
key->WriteStructuredClone(aWriter);
}
@ -476,7 +478,7 @@ StructuredCloneHolder::WriteFullySerializableObjects(JSContext* aCx,
{
// Handle WebRTC Certificate cloning
RTCCertificate* cert = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(RTCCertificate, aObj, cert))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(RTCCertificate, &obj, cert))) {
MOZ_ASSERT(NS_IsMainThread());
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_RTC_CERTIFICATE, 0) &&
cert->WriteStructuredClone(aWriter);
@ -484,8 +486,8 @@ StructuredCloneHolder::WriteFullySerializableObjects(JSContext* aCx,
}
#endif
if (NS_IsMainThread() && xpc::IsReflector(aObj)) {
nsCOMPtr<nsISupports> base = xpc::UnwrapReflectorToISupports(aObj);
if (NS_IsMainThread() && xpc::IsReflector(obj)) {
nsCOMPtr<nsISupports> base = xpc::UnwrapReflectorToISupports(obj);
nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(base);
if (principal) {
auto nsjsprincipals = nsJSPrincipals::get(principal);
@ -1011,10 +1013,12 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
return false;
}
JS::Rooted<JSObject*> obj(aCx, aObj);
// See if this is a File/Blob object.
{
Blob* blob = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) {
return WriteBlob(aWriter, blob, this);
}
}
@ -1022,7 +1026,7 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
// See if this is a Directory object.
{
Directory* directory = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Directory, aObj, directory))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(Directory, &obj, directory))) {
return WriteDirectory(aWriter, directory);
}
}
@ -1030,7 +1034,7 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
// See if this is a FileList object.
{
FileList* fileList = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, &obj, fileList))) {
return WriteFileList(aWriter, fileList, this);
}
}
@ -1038,7 +1042,7 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
// See if this is a FormData object.
{
FormData* formData = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(FormData, aObj, formData))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(FormData, &obj, formData))) {
return WriteFormData(aWriter, formData, this);
}
}
@ -1047,7 +1051,7 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
if (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread) {
ImageBitmap* imageBitmap = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageBitmap, aObj, imageBitmap))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageBitmap, &obj, imageBitmap))) {
return ImageBitmap::WriteStructuredClone(aWriter,
GetSurfaces(),
imageBitmap);
@ -1057,7 +1061,7 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
// See if this is a StructuredCloneBlob object.
{
StructuredCloneBlob* holder = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(StructuredCloneHolder, aObj, holder))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(StructuredCloneHolder, &obj, holder))) {
return holder->WriteStructuredClone(aCx, aWriter, this);
}
}
@ -1065,8 +1069,8 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
// See if this is a WasmModule.
if ((mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread) &&
JS::IsWasmModuleObject(aObj)) {
RefPtr<JS::WasmModule> module = JS::GetWasmModule(aObj);
JS::IsWasmModuleObject(obj)) {
RefPtr<JS::WasmModule> module = JS::GetWasmModule(obj);
MOZ_ASSERT(module);
return WriteWasmModule(aWriter, module, this);
@ -1174,9 +1178,11 @@ StructuredCloneHolder::CustomWriteTransferHandler(JSContext* aCx,
return false;
}
JS::Rooted<JSObject*> obj(aCx, aObj);
{
MessagePort* port = nullptr;
nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
nsresult rv = UNWRAP_OBJECT(MessagePort, &obj, port);
if (NS_SUCCEEDED(rv)) {
// We use aExtraData to store the index of this new port identifier.
*aExtraData = mPortIdentifiers.Length();
@ -1194,7 +1200,7 @@ StructuredCloneHolder::CustomWriteTransferHandler(JSContext* aCx,
if (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread) {
OffscreenCanvas* canvas = nullptr;
rv = UNWRAP_OBJECT(OffscreenCanvas, aObj, canvas);
rv = UNWRAP_OBJECT(OffscreenCanvas, &obj, canvas);
if (NS_SUCCEEDED(rv)) {
MOZ_ASSERT(canvas);
@ -1209,7 +1215,7 @@ StructuredCloneHolder::CustomWriteTransferHandler(JSContext* aCx,
}
ImageBitmap* bitmap = nullptr;
rv = UNWRAP_OBJECT(ImageBitmap, aObj, bitmap);
rv = UNWRAP_OBJECT(ImageBitmap, &obj, bitmap);
if (NS_SUCCEEDED(rv)) {
MOZ_ASSERT(bitmap);

Просмотреть файл

@ -3227,16 +3227,16 @@ nsDOMWindowUtils::GetFileId(JS::Handle<JS::Value> aFile, JSContext* aCx,
return NS_OK;
}
JSObject* obj = aFile.toObjectOrNull();
JS::Rooted<JSObject*> obj(aCx, aFile.toObjectOrNull());
IDBMutableFile* mutableFile = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(IDBMutableFile, obj, mutableFile))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(IDBMutableFile, &obj, mutableFile))) {
*_retval = mutableFile->GetFileId();
return NS_OK;
}
Blob* blob = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) {
*_retval = blob->GetFileId();
return NS_OK;
}
@ -3254,10 +3254,10 @@ nsDOMWindowUtils::GetFilePath(JS::HandleValue aFile, JSContext* aCx,
return NS_OK;
}
JSObject* obj = aFile.toObjectOrNull();
JS::Rooted<JSObject*> obj(aCx, aFile.toObjectOrNull());
File* file = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(File, obj, file))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(File, &obj, file))) {
nsString filePath;
ErrorResult rv;
file->GetMozFullPathInternal(filePath, rv);

Просмотреть файл

@ -1716,9 +1716,10 @@ XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
// be protected by read-only/non-configurable properties, and any functions
// we end up with should _always_ be living in our own scope (the XBL scope).
// Make sure to assert that.
JS::Rooted<JSObject*> maybeElement(cx, obj);
Element* element;
if (xpc::ObjectScope(wrapper)->IsContentXBLScope() &&
NS_SUCCEEDED(UNWRAP_OBJECT(Element, obj, element))) {
NS_SUCCEEDED(UNWRAP_OBJECT(Element, &maybeElement, element))) {
if (!nsContentUtils::LookupBindingMember(cx, element, id, desc)) {
return false;
}
@ -2306,14 +2307,15 @@ ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObjArg)
}
}
JS::Rooted<JSObject*> maybeObjLC(aCx, aObj);
nsObjectLoadingContent* htmlobject;
nsresult rv = UNWRAP_OBJECT(HTMLObjectElement, aObj, htmlobject);
nsresult rv = UNWRAP_OBJECT(HTMLObjectElement, &maybeObjLC, htmlobject);
if (NS_FAILED(rv)) {
rv = UnwrapObject<prototypes::id::HTMLEmbedElement,
HTMLSharedObjectElement>(aObj, htmlobject);
HTMLSharedObjectElement>(&maybeObjLC, htmlobject);
if (NS_FAILED(rv)) {
rv = UnwrapObject<prototypes::id::HTMLAppletElement,
HTMLSharedObjectElement>(aObj, htmlobject);
HTMLSharedObjectElement>(&maybeObjLC, htmlobject);
if (NS_FAILED(rv)) {
htmlobject = nullptr;
}
@ -2903,9 +2905,16 @@ GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp)
}
JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
// NOTE: we want to leave obj in its initial compartment, so don't want to
// pass it to UnwrapObject.
JS::Rooted<JSObject*> rootSelf(cx, obj);
void* self;
{
nsresult rv = UnwrapObject<void>(obj, self, protoID, info->depth);
binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
self,
protoID,
info->depth);
if (NS_FAILED(rv)) {
return ThrowInvalidThis(cx, args,
rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
@ -2942,9 +2951,16 @@ GenericPromiseReturningBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp
}
JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
// NOTE: we want to leave obj in its initial compartment, so don't want to
// pass it to UnwrapObject.
JS::Rooted<JSObject*> rootSelf(cx, obj);
void* self;
{
nsresult rv = UnwrapObject<void>(obj, self, protoID, info->depth);
binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
self,
protoID,
info->depth);
if (NS_FAILED(rv)) {
ThrowInvalidThis(cx, args, rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
protoID);
@ -2979,9 +2995,16 @@ GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp)
}
JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
// NOTE: we want to leave obj in its initial compartment, so don't want to
// pass it to UnwrapObject.
JS::Rooted<JSObject*> rootSelf(cx, obj);
void* self;
{
nsresult rv = UnwrapObject<void>(obj, self, protoID, info->depth);
binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
self,
protoID,
info->depth);
if (NS_FAILED(rv)) {
return ThrowInvalidThis(cx, args,
rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
@ -3014,9 +3037,16 @@ GenericBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp)
}
JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
// NOTE: we want to leave obj in its initial compartment, so don't want to
// pass it to UnwrapObject.
JS::Rooted<JSObject*> rootSelf(cx, obj);
void* self;
{
nsresult rv = UnwrapObject<void>(obj, self, protoID, info->depth);
binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
self,
protoID,
info->depth);
if (NS_FAILED(rv)) {
return ThrowInvalidThis(cx, args,
rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
@ -3052,9 +3082,16 @@ GenericPromiseReturningBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp
}
JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
// NOTE: we want to leave obj in its initial compartment, so don't want to
// pass it to UnwrapObject.
JS::Rooted<JSObject*> rootSelf(cx, obj);
void* self;
{
nsresult rv = UnwrapObject<void>(obj, self, protoID, info->depth);
binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf);
nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper,
self,
protoID,
info->depth);
if (NS_FAILED(rv)) {
ThrowInvalidThis(cx, args, rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
protoID);

Просмотреть файл

@ -186,45 +186,86 @@ IsDOMObject(JSObject* obj)
return IsDOMClass(js::GetObjectClass(obj));
}
// There are two valid ways to use UNWRAP_OBJECT: Either obj needs to
// be a MutableHandle<JSObject*>, or value needs to be a strong-reference
// smart pointer type (OwningNonNull or RefPtr or nsCOMPtr), in which case obj
// can be anything that converts to JSObject*.
#define UNWRAP_OBJECT(Interface, obj, value) \
mozilla::dom::UnwrapObject<mozilla::dom::prototypes::id::Interface, \
mozilla::dom::Interface##Binding::NativeType>(obj, value)
// Test whether the given object is an instance of the given interface.
#define IS_INSTANCE_OF(Interface, obj) \
mozilla::dom::IsInstanceOf<mozilla::dom::prototypes::id::Interface, \
mozilla::dom::Interface##Binding::NativeType>(obj)
// Unwrap the given non-wrapper object. This can be used with any obj that
// converts to JSObject*; as long as that JSObject* is live the return value
// will be valid.
#define UNWRAP_NON_WRAPPER_OBJECT(Interface, obj, value) \
mozilla::dom::UnwrapNonWrapperObject<mozilla::dom::prototypes::id::Interface, \
mozilla::dom::Interface##Binding::NativeType>(obj, value)
// Some callers don't want to set an exception when unwrapping fails
// (for example, overload resolution uses unwrapping to tell what sort
// of thing it's looking at).
// U must be something that a T* can be assigned to (e.g. T* or an RefPtr<T>).
template <class T, typename U>
//
// The obj argument will be mutated to point to CheckedUnwrap of itself if the
// passed-in value is not a DOM object and CheckedUnwrap succeeds.
//
// If mayBeWrapper is true, there are three valid ways to invoke
// UnwrapObjectInternal: Either obj needs to be a class wrapping a
// MutableHandle<JSObject*>, with an assignment operator that sets the handle to
// the given object, or U needs to be a strong-reference smart pointer type
// (OwningNonNull or RefPtr or nsCOMPtr), or the value being stored in "value"
// must not escape past being tested for falsiness immediately after the
// UnwrapObjectInternal call.
//
// If mayBeWrapper is false, obj can just be a JSObject*, and U anything that a
// T* can be assigned to.
namespace binding_detail {
template <class T, bool mayBeWrapper, typename U, typename V>
MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JSObject* obj, U& value, prototypes::ID protoID,
uint32_t protoDepth)
UnwrapObjectInternal(V& obj, U& value, prototypes::ID protoID,
uint32_t protoDepth)
{
/* First check to see whether we have a DOM object */
const DOMJSClass* domClass = GetDOMClass(obj);
if (!domClass) {
/* Maybe we have a security wrapper or outer window? */
if (!js::IsWrapper(obj)) {
/* Not a DOM object, not a wrapper, just bail */
return NS_ERROR_XPC_BAD_CONVERT_JS;
}
obj = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
if (!obj) {
return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
}
MOZ_ASSERT(!js::IsWrapper(obj));
domClass = GetDOMClass(obj);
if (!domClass) {
/* We don't have a DOM object */
return NS_ERROR_XPC_BAD_CONVERT_JS;
if (domClass) {
/* This object is a DOM object. Double-check that it is safely
castable to T by checking whether it claims to inherit from the
class identified by protoID. */
if (domClass->mInterfaceChain[protoDepth] == protoID) {
value = UnwrapDOMObject<T>(obj);
return NS_OK;
}
}
/* This object is a DOM object. Double-check that it is safely
castable to T by checking whether it claims to inherit from the
class identified by protoID. */
if (domClass->mInterfaceChain[protoDepth] == protoID) {
value = UnwrapDOMObject<T>(obj);
/* Maybe we have a security wrapper or outer window? */
if (!mayBeWrapper || !js::IsWrapper(obj)) {
/* Not a DOM object, not a wrapper, just bail */
return NS_ERROR_XPC_BAD_CONVERT_JS;
}
JSObject* unwrappedObj =
js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
if (!unwrappedObj) {
return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
}
MOZ_ASSERT(!js::IsWrapper(unwrappedObj));
// Recursive call is OK, because now we're using false for mayBeWrapper and
// we never reach this code if that boolean is false, so can't keep calling
// ourselves.
nsresult rv = UnwrapObjectInternal<T, false>(unwrappedObj, value,
protoID, protoDepth);
if (NS_SUCCEEDED(rv)) {
// It's very important to not update "obj" with the "unwrappedObj" value
// until we know the unwrap has succeeded. Otherwise, in a situation in
// which we have an overload of object and primitive we could end up
// converting to the primitive from the unwrappedObj, whereas we want to do
// it from the original object.
obj = unwrappedObj;
return NS_OK;
}
@ -232,12 +273,121 @@ UnwrapObject(JSObject* obj, U& value, prototypes::ID protoID,
return NS_ERROR_XPC_BAD_CONVERT_JS;
}
template <prototypes::ID PrototypeID, class T, typename U>
struct MutableObjectHandleWrapper {
explicit MutableObjectHandleWrapper(JS::MutableHandle<JSObject*> aHandle)
: mHandle(aHandle)
{
}
void operator=(JSObject* aObject)
{
MOZ_ASSERT(aObject);
mHandle.set(aObject);
}
operator JSObject*() const
{
return mHandle;
}
private:
JS::MutableHandle<JSObject*> mHandle;
};
struct MutableValueHandleWrapper {
explicit MutableValueHandleWrapper(JS::MutableHandle<JS::Value> aHandle)
: mHandle(aHandle)
{
}
void operator=(JSObject* aObject)
{
MOZ_ASSERT(aObject);
mHandle.setObject(*aObject);
}
operator JSObject*() const
{
return &mHandle.toObject();
}
private:
JS::MutableHandle<JS::Value> mHandle;
};
} // namespace binding_detail
// UnwrapObject overloads that ensure we have a MutableHandle to keep it alive.
template<prototypes::ID PrototypeID, class T, typename U>
MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JSObject* obj, U& value)
UnwrapObject(JS::MutableHandle<JSObject*> obj, U& value)
{
return UnwrapObject<T>(obj, value, PrototypeID,
PrototypeTraits<PrototypeID>::Depth);
binding_detail::MutableObjectHandleWrapper wrapper(obj);
return binding_detail::UnwrapObjectInternal<T, true>(
wrapper, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
}
template<prototypes::ID PrototypeID, class T, typename U>
MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JS::MutableHandle<JS::Value> obj, U& value)
{
MOZ_ASSERT(obj.isObject());
binding_detail::MutableValueHandleWrapper wrapper(obj);
return binding_detail::UnwrapObjectInternal<T, true>(
wrapper, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
}
// UnwrapObject overloads that ensure we have a strong ref to keep it alive.
template<prototypes::ID PrototypeID, class T, typename U>
MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JSObject* obj, RefPtr<U>& value)
{
return binding_detail::UnwrapObjectInternal<T, true>(
obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
}
template<prototypes::ID PrototypeID, class T, typename U>
MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JSObject* obj, nsCOMPtr<U>& value)
{
return binding_detail::UnwrapObjectInternal<T, true>(
obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
}
template<prototypes::ID PrototypeID, class T, typename U>
MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JSObject* obj, OwningNonNull<U>& value)
{
return binding_detail::UnwrapObjectInternal<T, true>(
obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
}
// An UnwrapObject overload that just calls one of the JSObject* ones.
template<prototypes::ID PrototypeID, class T, typename U>
MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JS::Handle<JS::Value> obj, U& value)
{
MOZ_ASSERT(obj.isObject());
return UnwrapObject<PrototypeID, T>(&obj.toObject(), value);
}
template<prototypes::ID PrototypeID, class T>
MOZ_ALWAYS_INLINE bool
IsInstanceOf(JSObject* obj)
{
void* ignored;
nsresult unwrapped = binding_detail::UnwrapObjectInternal<T, true>(
obj, ignored, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
return NS_SUCCEEDED(unwrapped);
}
template<prototypes::ID PrototypeID, class T, typename U>
MOZ_ALWAYS_INLINE nsresult
UnwrapNonWrapperObject(JSObject* obj, U& value)
{
MOZ_ASSERT(!js::IsWrapper(obj));
return binding_detail::UnwrapObjectInternal<T, false>(
obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
}
MOZ_ALWAYS_INLINE bool

Просмотреть файл

@ -4353,18 +4353,16 @@ class CastableObjectUnwrapper():
$*{codeOnFailure}
}
}
JS::Rooted<JS::Value> maybeUncheckedVal(cx, JS::ObjectValue(*maybeUncheckedObj));
""",
codeOnFailure=(codeOnFailure % { 'securityError': 'true'}))
self.substitution["source"] = "maybeUncheckedVal"
self.substitution["mutableSource"] = "&maybeUncheckedVal"
self.substitution["source"] = "maybeUncheckedObj"
self.substitution["mutableSource"] = "&maybeUncheckedObj"
xpconnectUnwrap = dedent("""
nsresult rv;
{ // Scope for the JSAutoCompartment, because we only
// want to be in that compartment for the UnwrapArg call.
JS::Rooted<JSObject*> source(cx, &${source}.toObject());
JSAutoCompartment ac(cx, source);
rv = UnwrapArg<${type}>(cx, source, getter_AddRefs(objPtr));
JSAutoCompartment ac(cx, ${source});
rv = UnwrapArg<${type}>(cx, ${source}, getter_AddRefs(objPtr));
}
""")
else:
@ -4425,7 +4423,7 @@ class CastableObjectUnwrapper():
$*{uncheckedObjDecl}
{
$*{uncheckedObjGet}
nsresult rv = UnwrapObject<${protoID}, ${type}>(&${source}.toObject(), ${target});
nsresult rv = UnwrapObject<${protoID}, ${type}>(${mutableSource}, ${target});
if (NS_FAILED(rv)) {
$*{codeOnFailure}
}

Просмотреть файл

@ -219,8 +219,14 @@ WebIDLGlobalNameHash::DefineIfEnabled(JSContext* aCx,
}
{
// It's safe to pass "&global" here, because we've already unwrapped it, but
// for general sanity better to not have debug code even having the
// appearance of mutating things that opt code uses.
#ifdef DEBUG
JS::Rooted<JSObject*> temp(aCx, global);
DebugOnly<nsGlobalWindow*> win;
MOZ_ASSERT(NS_SUCCEEDED(UNWRAP_OBJECT(Window, global, win)));
MOZ_ASSERT(NS_SUCCEEDED(UNWRAP_OBJECT(Window, &temp, win)));
#endif
}
if (checkEnabledForScope && !checkEnabledForScope(aCx, global)) {

Просмотреть файл

@ -211,8 +211,11 @@ StructuredCloneWriteCallback(JSContext* aCx,
return JS_WriteBytes(aWriter, &value, sizeof(value));
}
// UNWRAP_OBJECT calls might mutate this.
JS::Rooted<JSObject*> obj(aCx, aObj);
IDBMutableFile* mutableFile;
if (NS_SUCCEEDED(UNWRAP_OBJECT(IDBMutableFile, aObj, mutableFile))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(IDBMutableFile, &obj, mutableFile))) {
if (cloneWriteInfo->mDatabase->IsFileHandleDisabled()) {
return false;
}
@ -281,7 +284,7 @@ StructuredCloneWriteCallback(JSContext* aCx,
{
Blob* blob = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) {
ErrorResult rv;
uint64_t size = blob->GetSize(rv);
MOZ_ASSERT(!rv.Failed());

Просмотреть файл

@ -157,8 +157,9 @@ WebVTTListener::OnCue(JS::Handle<JS::Value> aCue, JSContext* aCx)
return NS_ERROR_FAILURE;
}
JS::Rooted<JSObject*> obj(aCx, &aCue.toObject());
TextTrackCue* cue = nullptr;
nsresult rv = UNWRAP_OBJECT(VTTCue, &aCue.toObject(), cue);
nsresult rv = UNWRAP_OBJECT(VTTCue, &obj, cue);
NS_ENSURE_SUCCESS(rv, rv);
cue->SetTrackElement(mElement);

Просмотреть файл

@ -403,13 +403,13 @@ MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
// Here we want to check if the transerable object list contains
// this port.
for (uint32_t i = 0; i < aTransferable.Length(); ++i) {
JSObject* object = aTransferable[i];
JS::Rooted<JSObject*> object(aCx, aTransferable[i]);
if (!object) {
continue;
}
MessagePort* port = nullptr;
nsresult rv = UNWRAP_OBJECT(MessagePort, object, port);
nsresult rv = UNWRAP_OBJECT(MessagePort, &object, port);
if (NS_SUCCEEDED(rv) && port == this) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return;

Просмотреть файл

@ -989,7 +989,7 @@ Notification::Constructor(const GlobalObject& aGlobal,
ErrorResult& aRv)
{
// FIXME(nsm): If the sticky flag is set, throw an error.
ServiceWorkerGlobalScope* scope = nullptr;
RefPtr<ServiceWorkerGlobalScope> scope;
UNWRAP_OBJECT(ServiceWorkerGlobalScope, aGlobal.Get(), scope);
if (scope) {
aRv.ThrowTypeError<MSG_NOTIFICATION_NO_CONSTRUCTOR_IN_SERVICEWORKER>();

Просмотреть файл

@ -1611,7 +1611,7 @@ PresentationPresentingInfo::ResolvedCallback(JSContext* aCx,
// Start to listen to document state change event |STATE_TRANSFERRING|.
// Use Element to support both HTMLIFrameElement and nsXULElement.
Element* frame = nullptr;
nsresult rv = UNWRAP_OBJECT(Element, obj, frame);
nsresult rv = UNWRAP_OBJECT(Element, &obj, frame);
if (NS_WARN_IF(!frame)) {
ReplyError(NS_ERROR_DOM_OPERATION_ERR);
return;

Просмотреть файл

@ -284,14 +284,13 @@ NativeHandlerCallback(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
{
JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
JS::Rooted<JS::Value> v(aCx,
js::GetFunctionNativeReserved(&args.callee(),
SLOT_NATIVEHANDLER));
JS::Value v = js::GetFunctionNativeReserved(&args.callee(),
SLOT_NATIVEHANDLER);
MOZ_ASSERT(v.isObject());
JS::Rooted<JSObject*> obj(aCx, &v.toObject());
PromiseNativeHandler* handler = nullptr;
if (NS_FAILED(UNWRAP_OBJECT(PromiseNativeHandler, &v.toObject(),
handler))) {
if (NS_FAILED(UNWRAP_OBJECT(PromiseNativeHandler, &obj, handler))) {
return Throw(aCx, NS_ERROR_UNEXPECTED);
}

Просмотреть файл

@ -1525,7 +1525,7 @@ CacheCreator::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
Cache* cache = nullptr;
nsresult rv = UNWRAP_OBJECT(Cache, obj, cache);
nsresult rv = UNWRAP_OBJECT(Cache, &obj, cache);
if (NS_WARN_IF(NS_FAILED(rv))) {
FailLoaders(NS_ERROR_FAILURE);
return;
@ -1671,7 +1671,7 @@ CacheScriptLoader::ResolvedCallback(JSContext* aCx,
JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
mozilla::dom::Response* response = nullptr;
rv = UNWRAP_OBJECT(Response, obj, response);
rv = UNWRAP_OBJECT(Response, &obj, response);
if (NS_WARN_IF(NS_FAILED(rv))) {
Fail(rv);
return;

Просмотреть файл

@ -35,9 +35,7 @@ ServiceWorkerVisible(JSContext* aCx, JSObject* aObj)
return Preferences::GetBool("dom.serviceWorkers.enabled", false);
}
ServiceWorkerGlobalScope* scope = nullptr;
nsresult rv = UNWRAP_OBJECT(ServiceWorkerGlobalScope, aObj, scope);
return NS_SUCCEEDED(rv);
return IS_INSTANCE_OF(ServiceWorkerGlobalScope, aObj);
}
ServiceWorker::ServiceWorker(nsPIDOMWindowInner* aWindow,

Просмотреть файл

@ -473,7 +473,7 @@ private:
Request* request;
JS::Rooted<JSObject*> requestObj(aCx, &val.toObject());
if (NS_WARN_IF(NS_FAILED(UNWRAP_OBJECT(Request, requestObj, request)))) {
if (NS_WARN_IF(NS_FAILED(UNWRAP_OBJECT(Request, &requestObj, request)))) {
return;
};
@ -510,7 +510,7 @@ private:
}
Cache* cache = nullptr;
rv = UNWRAP_OBJECT(Cache, obj, cache);
rv = UNWRAP_OBJECT(Cache, &obj, cache);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
@ -1124,7 +1124,7 @@ CompareCache::ManageValueResult(JSContext* aCx, JS::Handle<JS::Value> aValue)
}
Response* response = nullptr;
nsresult rv = UNWRAP_OBJECT(Response, obj, response);
nsresult rv = UNWRAP_OBJECT(Response, &obj, response);
if (NS_WARN_IF(NS_FAILED(rv))) {
Finish(rv, false);
return;

Просмотреть файл

@ -1050,11 +1050,11 @@ public:
if (aWorkerPrivate) {
WorkerGlobalScope* globalScope = nullptr;
UNWRAP_OBJECT(WorkerGlobalScope, global, globalScope);
UNWRAP_OBJECT(WorkerGlobalScope, &global, globalScope);
if (!globalScope) {
WorkerDebuggerGlobalScope* globalScope = nullptr;
UNWRAP_OBJECT(WorkerDebuggerGlobalScope, global, globalScope);
UNWRAP_OBJECT(WorkerDebuggerGlobalScope, &global, globalScope);
MOZ_ASSERT_IF(globalScope, globalScope->GetWrapperPreserveColor() == global);
if (globalScope || IsDebuggerSandbox(global)) {
@ -7112,8 +7112,9 @@ GetWorkerCrossThreadDispatcher(JSContext* aCx, const JS::Value& aWorker)
return nullptr;
}
JS::Rooted<JSObject*> obj(aCx, &aWorker.toObject());
WorkerPrivate* w = nullptr;
UNWRAP_OBJECT(Worker, &aWorker.toObject(), w);
UNWRAP_OBJECT(Worker, &obj, w);
MOZ_ASSERT(w);
return w->GetCrossThreadDispatcher();
}

Просмотреть файл

@ -1104,17 +1104,13 @@ BEGIN_WORKERS_NAMESPACE
bool
IsWorkerGlobal(JSObject* object)
{
nsIGlobalObject* globalObject = nullptr;
return NS_SUCCEEDED(UNWRAP_OBJECT(WorkerGlobalScope, object,
globalObject)) && !!globalObject;
return IS_INSTANCE_OF(WorkerGlobalScope, object);
}
bool
IsDebuggerGlobal(JSObject* object)
{
nsIGlobalObject* globalObject = nullptr;
return NS_SUCCEEDED(UNWRAP_OBJECT(WorkerDebuggerGlobalScope, object,
globalObject)) && !!globalObject;
return IS_INSTANCE_OF(WorkerDebuggerGlobalScope, object);
}
bool

Просмотреть файл

@ -415,8 +415,10 @@ nsXBLProtoImplField::InstallField(JS::Handle<JSObject*> aBoundNode,
JSAddonId* addonId = MapURIToAddonID(aBindingDocURI);
// Note: the UNWRAP_OBJECT may mutate boundNode; don't use it after that call.
JS::Rooted<JSObject*> boundNode(jsapi.cx(), aBoundNode);
Element* boundElement = nullptr;
rv = UNWRAP_OBJECT(Element, aBoundNode, boundElement);
rv = UNWRAP_OBJECT(Element, &boundNode, boundElement);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

Просмотреть файл

@ -75,7 +75,7 @@ XPathExpression::EvaluateWithContext(JSContext* aCx,
JS::Handle<JSObject*> aInResult,
ErrorResult& aRv)
{
XPathResult* inResult = nullptr;
RefPtr<XPathResult> inResult;
if (aInResult) {
nsresult rv = UNWRAP_OBJECT(XPathResult, aInResult, inResult);
if (NS_FAILED(rv) && rv != NS_ERROR_XPC_BAD_CONVERT_JS) {

Просмотреть файл

@ -150,8 +150,9 @@ public:
JS::Handle<JSObject*> aObj)
{
{
JS::Rooted<JSObject*> obj(aCx, aObj);
Blob* blob = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) {
BlobImpl* blobImpl = blob->Impl();
MOZ_ASSERT(blobImpl);

Просмотреть файл

@ -1708,12 +1708,10 @@ nsXPCComponents_Exception::HasInstance(nsIXPConnectWrappedNative* wrapper,
{
using namespace mozilla::dom;
RootedValue v(cx, val);
if (bp) {
Exception* e;
*bp = (v.isObject() &&
NS_SUCCEEDED(UNWRAP_OBJECT(Exception, &v.toObject(), e))) ||
JSValIsInterfaceOfType(cx, v, NS_GET_IID(nsIException));
*bp = (val.isObject() &&
IS_INSTANCE_OF(Exception, &val.toObject())) ||
JSValIsInterfaceOfType(cx, val, NS_GET_IID(nsIException));
}
return NS_OK;
}
@ -2539,7 +2537,7 @@ nsXPCComponents_Utils::ImportGlobalProperties(HandleValue aPropertyList,
// Don't allow doing this if the global is a Window
nsGlobalWindow* win;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Window, global, win))) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(Window, &global, win))) {
return NS_ERROR_NOT_AVAILABLE;
}

Просмотреть файл

@ -514,7 +514,7 @@ WindowOrNull(JSObject* aObj)
MOZ_ASSERT(!js::IsWrapper(aObj));
nsGlobalWindow* win = nullptr;
UNWRAP_OBJECT(Window, aObj, win);
UNWRAP_NON_WRAPPER_OBJECT(Window, aObj, win);
return win;
}

Просмотреть файл

@ -252,8 +252,9 @@ nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(JSContext* cx,
if (jsexception.isObject()) {
// XPConnect may have constructed an object to represent a
// C++ QI failure. See if that is the case.
JS::Rooted<JSObject*> exceptionObj(cx, &jsexception.toObject());
Exception* e = nullptr;
UNWRAP_OBJECT(Exception, &jsexception.toObject(), e);
UNWRAP_OBJECT(Exception, &exceptionObj, e);
if (e &&
NS_SUCCEEDED(e->GetResult(&rv)) &&