mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-11 01:57:00 +00:00
Bug 895758. Make the global scope polluter a proxy. r=bzbarsky
This commit is contained in:
parent
6595b4e5da
commit
ac70c03afa
181
dom/base/WindowNamedPropertiesHandler.cpp
Normal file
181
dom/base/WindowNamedPropertiesHandler.cpp
Normal file
@ -0,0 +1,181 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et tw=78: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WindowNamedPropertiesHandler.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsHTMLDocument.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "xpcprivate.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
bool
|
||||
WindowNamedPropertiesHandler::getOwnPropertyDescriptor(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aProxy,
|
||||
JS::Handle<jsid> aId,
|
||||
JS::MutableHandle<JSPropertyDescriptor> aDesc,
|
||||
unsigned aFlags)
|
||||
{
|
||||
if (!JSID_IS_STRING(aId)) {
|
||||
// Nothing to do if we're resolving a non-string property.
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject* global = JS_GetGlobalForObject(aCx, aProxy);
|
||||
nsresult rv =
|
||||
nsDOMClassInfo::ScriptSecurityManager()->CheckPropertyAccess(aCx, global,
|
||||
"Window", aId,
|
||||
nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
|
||||
if (NS_FAILED(rv)) {
|
||||
// The security check failed. The security manager set a JS exception for
|
||||
// us.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HasPropertyOnPrototype(aCx, aProxy, aId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsDependentJSString str(aId);
|
||||
|
||||
// Grab the DOM window.
|
||||
XPCWrappedNative* wrapper = XPCWrappedNative::Get(global);
|
||||
nsCOMPtr<nsPIDOMWindow> piWin = do_QueryWrappedNative(wrapper);
|
||||
MOZ_ASSERT(piWin);
|
||||
nsGlobalWindow* win = static_cast<nsGlobalWindow*>(piWin.get());
|
||||
if (win->GetLength() > 0) {
|
||||
nsCOMPtr<nsIDOMWindow> childWin = win->GetChildWindow(str);
|
||||
if (childWin) {
|
||||
// We found a subframe of the right name. Shadowing via |var foo| in
|
||||
// global scope is still allowed, since |var| only looks up |own|
|
||||
// properties. But unqualified shadowing will fail, per-spec.
|
||||
JS::Rooted<JS::Value> v(aCx);
|
||||
if (!WrapObject(aCx, aProxy, childWin, &v)) {
|
||||
return false;
|
||||
}
|
||||
aDesc.object().set(aProxy);
|
||||
aDesc.value().set(v);
|
||||
aDesc.setAttributes(JSPROP_ENUMERATE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// The rest of this function is for HTML documents only.
|
||||
nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(win->GetExtantDoc());
|
||||
if (!htmlDoc) {
|
||||
return true;
|
||||
}
|
||||
nsHTMLDocument *document = static_cast<nsHTMLDocument*>(htmlDoc.get());
|
||||
|
||||
Element *element = document->GetElementById(str);
|
||||
if (element) {
|
||||
JS::Rooted<JS::Value> v(aCx);
|
||||
if (!WrapObject(aCx, aProxy, element, &v)) {
|
||||
return false;
|
||||
}
|
||||
aDesc.object().set(aProxy);
|
||||
aDesc.value().set(v);
|
||||
aDesc.setAttributes(JSPROP_ENUMERATE);
|
||||
return true;
|
||||
}
|
||||
|
||||
nsWrapperCache* cache;
|
||||
nsISupports* result = document->ResolveName(str, &cache);
|
||||
if (!result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> v(aCx);
|
||||
if (!WrapObject(aCx, aProxy, result, cache, nullptr, &v)) {
|
||||
return false;
|
||||
}
|
||||
aDesc.object().set(aProxy);
|
||||
aDesc.value().set(v);
|
||||
aDesc.setAttributes(JSPROP_ENUMERATE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WindowNamedPropertiesHandler::defineProperty(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aProxy,
|
||||
JS::Handle<jsid> aId,
|
||||
JS::MutableHandle<JSPropertyDescriptor> aDesc)
|
||||
{
|
||||
ErrorResult rv;
|
||||
rv.ThrowTypeError(MSG_DEFINEPROPERTY_ON_GSP);
|
||||
rv.ReportTypeError(aCx);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
WindowNamedPropertiesHandler::getOwnPropertyNames(JSContext *aCx,
|
||||
JS::Handle<JSObject*> aProxy,
|
||||
JS::AutoIdVector& aProps)
|
||||
{
|
||||
// Grab the DOM window.
|
||||
JSObject* global = JS_GetGlobalForObject(aCx, aProxy);
|
||||
XPCWrappedNative* wrapper = XPCWrappedNative::Get(global);
|
||||
nsCOMPtr<nsPIDOMWindow> piWin = do_QueryWrappedNative(wrapper);
|
||||
MOZ_ASSERT(piWin);
|
||||
nsGlobalWindow* win = static_cast<nsGlobalWindow*>(piWin.get());
|
||||
nsTArray<nsString> names;
|
||||
win->GetSupportedNames(names);
|
||||
if (!AppendNamedPropertyIds(aCx, aProxy, names, false, aProps)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
names.Clear();
|
||||
nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(win->GetExtantDoc());
|
||||
if (!htmlDoc) {
|
||||
return true;
|
||||
}
|
||||
nsHTMLDocument *document = static_cast<nsHTMLDocument*>(htmlDoc.get());
|
||||
document->GetSupportedNames(names);
|
||||
|
||||
JS::AutoIdVector docProps(aCx);
|
||||
if (!AppendNamedPropertyIds(aCx, aProxy, names, false, docProps)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return js::AppendUnique(aCx, aProps, docProps);
|
||||
}
|
||||
|
||||
bool
|
||||
WindowNamedPropertiesHandler::delete_(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aProxy,
|
||||
JS::Handle<jsid> aId, bool* aBp)
|
||||
{
|
||||
*aBp = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
WindowNamedPropertiesHandler::Install(JSContext *aCx,
|
||||
JS::Handle<JSObject*> aProto)
|
||||
{
|
||||
JS::Rooted<JSObject*> protoProto(aCx);
|
||||
if (!::JS_GetPrototype(aCx, aProto, &protoProto)) {
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> gsp(aCx);
|
||||
gsp = js::NewProxyObject(aCx, WindowNamedPropertiesHandler::getInstance(),
|
||||
JS::NullHandleValue, protoProto,
|
||||
js::GetGlobalForObjectCrossCompartment(aProto));
|
||||
if (!gsp) {
|
||||
return;
|
||||
}
|
||||
|
||||
// And then set the prototype of the interface prototype object to be the
|
||||
// global scope polluter.
|
||||
::JS_SplicePrototype(aCx, aProto, gsp);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
74
dom/base/WindowNamedPropertiesHandler.h
Normal file
74
dom/base/WindowNamedPropertiesHandler.h
Normal file
@ -0,0 +1,74 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et tw=78: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_WindowNamedPropertiesHandler_h
|
||||
#define mozilla_dom_WindowNamedPropertiesHandler_h__
|
||||
|
||||
#include "jsproxy.h"
|
||||
#include "mozilla/dom/DOMJSProxyHandler.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class WindowNamedPropertiesHandler : public BaseDOMProxyHandler
|
||||
{
|
||||
public:
|
||||
WindowNamedPropertiesHandler() : BaseDOMProxyHandler(nullptr)
|
||||
{
|
||||
setHasPrototype(true);
|
||||
}
|
||||
virtual bool
|
||||
preventExtensions(JSContext* aCx, JS::Handle<JSObject*> aProxy) MOZ_OVERRIDE
|
||||
{
|
||||
// Throw a TypeError, per WebIDL.
|
||||
JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr,
|
||||
JSMSG_CANT_CHANGE_EXTENSIBILITY);
|
||||
return false;
|
||||
}
|
||||
virtual bool
|
||||
getOwnPropertyDescriptor(JSContext* aCx, JS::Handle<JSObject*> aProxy,
|
||||
JS::Handle<jsid> aId,
|
||||
JS::MutableHandle<JSPropertyDescriptor> aDesc,
|
||||
unsigned aFlags) MOZ_OVERRIDE;
|
||||
virtual bool
|
||||
defineProperty(JSContext* aCx, JS::Handle<JSObject*> aProxy,
|
||||
JS::Handle<jsid> aId,
|
||||
JS::MutableHandle<JSPropertyDescriptor> aDesc) MOZ_OVERRIDE;
|
||||
virtual bool
|
||||
getOwnPropertyNames(JSContext* aCx, JS::Handle<JSObject*> aProxy,
|
||||
JS::AutoIdVector& aProps) MOZ_OVERRIDE;
|
||||
virtual bool
|
||||
delete_(JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
|
||||
bool* aBp) MOZ_OVERRIDE;
|
||||
virtual bool
|
||||
isExtensible(JSContext* aCx, JS::Handle<JSObject*> aProxy,
|
||||
bool* aIsExtensible) MOZ_OVERRIDE
|
||||
{
|
||||
*aIsExtensible = true;
|
||||
return true;
|
||||
}
|
||||
virtual const char*
|
||||
className(JSContext *aCx, JS::Handle<JSObject*> aProxy) MOZ_OVERRIDE
|
||||
{
|
||||
return "WindowProperties";
|
||||
}
|
||||
|
||||
static WindowNamedPropertiesHandler*
|
||||
getInstance()
|
||||
{
|
||||
static WindowNamedPropertiesHandler instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
// For Install, aProto is the proto of the Window we're associated with.
|
||||
static void
|
||||
Install(JSContext *aCx, JS::Handle<JSObject*> aProto);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_WindowNamedPropertiesHandler_h */
|
@ -98,6 +98,7 @@ CPP_SOURCES += [
|
||||
'nsWindowMemoryReporter.cpp',
|
||||
'nsWindowRoot.cpp',
|
||||
'nsWrapperCache.cpp',
|
||||
'WindowNamedPropertiesHandler.cpp',
|
||||
]
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
|
@ -251,6 +251,7 @@ using mozilla::dom::workers::ResolveWorkerClasses;
|
||||
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "WindowNamedPropertiesHandler.h"
|
||||
|
||||
#ifdef MOZ_TIME_MANAGER
|
||||
#include "TimeManager.h"
|
||||
@ -2316,70 +2317,17 @@ nsWindowSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
|
||||
return SetParentToWindow(win, parentObj);
|
||||
}
|
||||
|
||||
static JSClass sGlobalScopePolluterClass = {
|
||||
"Global Scope Polluter",
|
||||
JSCLASS_NEW_RESOLVE,
|
||||
JS_PropertyStub,
|
||||
JS_DeletePropertyStub,
|
||||
nsWindowSH::GlobalScopePolluterGetProperty,
|
||||
JS_StrictPropertyStub,
|
||||
JS_EnumerateStub,
|
||||
(JSResolveOp)nsWindowSH::GlobalScopePolluterNewResolve,
|
||||
JS_ConvertStub,
|
||||
nullptr
|
||||
};
|
||||
|
||||
|
||||
// static
|
||||
bool
|
||||
nsWindowSH::GlobalScopePolluterGetProperty(JSContext *cx, JS::Handle<JSObject*> obj,
|
||||
JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp)
|
||||
NS_IMETHODIMP
|
||||
nsWindowSH::PostCreatePrototype(JSContext* aCx, JSObject* aProto)
|
||||
{
|
||||
// Someone is accessing a element by referencing its name/id in the
|
||||
// global scope, do a security check to make sure that's ok.
|
||||
nsresult rv = nsDOMClassInfo::PostCreatePrototype(aCx, aProto);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsresult rv =
|
||||
sSecMan->CheckPropertyAccess(cx, ::JS_GetGlobalForObject(cx, obj),
|
||||
"Window", id,
|
||||
nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// The security check failed. The security manager set a JS
|
||||
// exception for us.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Gets a subframe.
|
||||
static bool
|
||||
ChildWindowGetter(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JS::Value> vp)
|
||||
{
|
||||
MOZ_ASSERT(JSID_IS_STRING(id));
|
||||
// Grab the native DOM window.
|
||||
vp.setUndefined();
|
||||
nsCOMPtr<nsISupports> winSupports =
|
||||
do_QueryInterface(nsDOMClassInfo::XPConnect()->GetNativeOfWrapper(cx, obj));
|
||||
if (!winSupports)
|
||||
return true;
|
||||
nsGlobalWindow *win = nsGlobalWindow::FromSupports(winSupports);
|
||||
|
||||
// Find the child, if it exists.
|
||||
nsDependentJSString name(id);
|
||||
nsCOMPtr<nsIDOMWindow> child = win->GetChildWindow(name);
|
||||
if (!child)
|
||||
return true;
|
||||
|
||||
// Wrap the child for JS.
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
nsresult rv = WrapNative(cx, JS::CurrentGlobalOrNull(cx), child,
|
||||
/* aAllowWrapping = */ true, v.address());
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
vp.set(v);
|
||||
return true;
|
||||
// We should probably move this into the CreateInterfaceObjects for Window
|
||||
// once it is on WebIDL bindings.
|
||||
JS::Rooted<JSObject*> proto(aCx, aProto);
|
||||
WindowNamedPropertiesHandler::Install(aCx, proto);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsHTMLDocument*
|
||||
@ -2390,177 +2338,6 @@ GetDocument(JSObject *obj)
|
||||
static_cast<nsINode*>(JS_GetPrivate(obj)));
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
nsWindowSH::GlobalScopePolluterNewResolve(JSContext *cx, JS::Handle<JSObject*> obj,
|
||||
JS::Handle<jsid> id, unsigned flags,
|
||||
JS::MutableHandle<JSObject*> objp)
|
||||
{
|
||||
if (!JSID_IS_STRING(id)) {
|
||||
// Nothing to do if we're resolving a non-string property.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Crash reports from the wild seem to get here during shutdown when there's
|
||||
// no more XPConnect singleton.
|
||||
nsIXPConnect *xpc = XPConnect();
|
||||
NS_ENSURE_TRUE(xpc, true);
|
||||
|
||||
// Grab the DOM window.
|
||||
JSObject *global = JS_GetGlobalForObject(cx, obj);
|
||||
nsISupports *globalNative = xpc->GetNativeOfWrapper(cx, global);
|
||||
nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(globalNative);
|
||||
MOZ_ASSERT(piWin);
|
||||
nsGlobalWindow* win = static_cast<nsGlobalWindow*>(piWin.get());
|
||||
|
||||
if (win->GetLength() > 0) {
|
||||
nsDependentJSString name(id);
|
||||
nsCOMPtr<nsIDOMWindow> child_win = win->GetChildWindow(name);
|
||||
if (child_win) {
|
||||
// We found a subframe of the right name, so define the property
|
||||
// on the GSP. This property is a read-only accessor. Shadowing via
|
||||
// |var foo| in global scope is still allowed, since |var| only looks
|
||||
// up |own| properties. But unqualified shadowing will fail, per-spec.
|
||||
if (!JS_DefinePropertyById(cx, obj, id, JS::UndefinedValue(),
|
||||
ChildWindowGetter, JS_StrictPropertyStub,
|
||||
JSPROP_SHARED | JSPROP_ENUMERATE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
objp.set(obj);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> proto(cx);
|
||||
if (!::JS_GetPrototype(cx, obj, &proto)) {
|
||||
return false;
|
||||
}
|
||||
bool hasProp;
|
||||
|
||||
if (!proto || !::JS_HasPropertyById(cx, proto, id, &hasProp) ||
|
||||
hasProp) {
|
||||
// No prototype, or the property exists on the prototype. Do
|
||||
// nothing.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// The rest of this function is for HTML documents only.
|
||||
//
|
||||
nsCOMPtr<nsIHTMLDocument> htmlDoc =
|
||||
do_QueryInterface(win->GetExtantDoc());
|
||||
if (!htmlDoc)
|
||||
return true;
|
||||
nsHTMLDocument *document = static_cast<nsHTMLDocument*>(htmlDoc.get());
|
||||
|
||||
nsDependentJSString str(id);
|
||||
nsCOMPtr<nsISupports> result;
|
||||
nsWrapperCache *cache;
|
||||
{
|
||||
Element *element = document->GetElementById(str);
|
||||
result = element;
|
||||
cache = element;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
result = document->ResolveName(str, &cache);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
nsresult rv = WrapNative(cx, obj, result, cache, true, v.address(),
|
||||
getter_AddRefs(holder));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
if (!JS_WrapValue(cx, v.address()) ||
|
||||
!JS_DefinePropertyById(cx, obj, id, v, JS_PropertyStub, JS_StrictPropertyStub, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
objp.set(obj);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
nsWindowSH::InvalidateGlobalScopePolluter(JSContext *cx,
|
||||
JS::Handle<JSObject*> aObj)
|
||||
{
|
||||
JS::Rooted<JSObject*> proto(cx);
|
||||
JS::Rooted<JSObject*> obj(cx, aObj);
|
||||
|
||||
for (;;) {
|
||||
if (!::JS_GetPrototype(cx, obj, &proto)) {
|
||||
return false;
|
||||
}
|
||||
if (!proto) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (JS_GetClass(proto) == &sGlobalScopePolluterClass) {
|
||||
|
||||
JS::Rooted<JSObject*> proto_proto(cx);
|
||||
if (!::JS_GetPrototype(cx, proto, &proto_proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pull the global scope polluter out of the prototype chain so
|
||||
// that it can be freed.
|
||||
::JS_SplicePrototype(cx, obj, proto_proto);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
obj = proto;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
nsWindowSH::InstallGlobalScopePolluter(JSContext *cx, JS::Handle<JSObject*> obj)
|
||||
{
|
||||
JS::Rooted<JSObject*> gsp(cx, ::JS_NewObjectWithUniqueType(cx, &sGlobalScopePolluterClass, nullptr, obj));
|
||||
if (!gsp) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> o(cx, obj), proto(cx);
|
||||
|
||||
// Find the place in the prototype chain where we want this global
|
||||
// scope polluter (right before Object.prototype).
|
||||
|
||||
for (;;) {
|
||||
if (!::JS_GetPrototype(cx, o, &proto)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
if (!proto) {
|
||||
break;
|
||||
}
|
||||
if (JS_GetClass(proto) == sObjectClass) {
|
||||
// Set the global scope polluters prototype to Object.prototype
|
||||
::JS_SplicePrototype(cx, gsp, proto);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
o = proto;
|
||||
}
|
||||
|
||||
// And then set the prototype of the object whose prototype was
|
||||
// Object.prototype to be the global scope polluter.
|
||||
::JS_SplicePrototype(cx, o, gsp);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
struct ResolveGlobalNameClosure
|
||||
{
|
||||
JSContext* cx;
|
||||
|
@ -136,6 +136,10 @@ public:
|
||||
{
|
||||
return sXPConnect;
|
||||
}
|
||||
static nsIScriptSecurityManager *ScriptSecurityManager()
|
||||
{
|
||||
return sSecMan;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend nsIClassInfo* NS_GetDOMClassInfoInstance(nsDOMClassInfoID aID);
|
||||
@ -307,6 +311,7 @@ protected:
|
||||
public:
|
||||
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
|
||||
JSObject *globalObj, JSObject **parentObj) MOZ_OVERRIDE;
|
||||
NS_IMETHOD PostCreatePrototype(JSContext * cx, JSObject * proto) MOZ_OVERRIDE;
|
||||
#ifdef DEBUG
|
||||
NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj) MOZ_OVERRIDE
|
||||
|
@ -86,14 +86,9 @@ nsDOMWindowList::GetLength(uint32_t* aLength)
|
||||
already_AddRefed<nsIDOMWindow>
|
||||
nsDOMWindowList::IndexedGetter(uint32_t aIndex, bool& aFound)
|
||||
{
|
||||
EnsureFresh();
|
||||
|
||||
aFound = false;
|
||||
NS_ENSURE_TRUE(mDocShellNode, nullptr);
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> item;
|
||||
mDocShellNode->GetChildAt(aIndex, getter_AddRefs(item));
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> item = GetDocShellTreeItemAt(aIndex);
|
||||
if (!item) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "nsIDOMWindowCollection.h"
|
||||
#include "nsString.h"
|
||||
#include <stdint.h>
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
|
||||
class nsIDocShellTreeNode;
|
||||
class nsIDocShell;
|
||||
@ -29,6 +30,15 @@ public:
|
||||
|
||||
//local methods
|
||||
NS_IMETHOD SetDocShell(nsIDocShell* aDocShell);
|
||||
already_AddRefed<nsIDocShellTreeItem> GetDocShellTreeItemAt(uint32_t aIndex)
|
||||
{
|
||||
EnsureFresh();
|
||||
nsCOMPtr<nsIDocShellTreeItem> item;
|
||||
if (mDocShellNode) {
|
||||
mDocShellNode->GetChildAt(aIndex, getter_AddRefs(item));
|
||||
}
|
||||
return item.forget();
|
||||
}
|
||||
|
||||
protected:
|
||||
// Note: this function may flush and cause mDocShellNode to become null.
|
||||
|
@ -2279,9 +2279,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
||||
if (aDocument != oldDoc) {
|
||||
JS::Rooted<JSObject*> obj(cx, currentInner->mJSObject);
|
||||
xpc_UnmarkGrayObject(obj);
|
||||
if (!nsWindowSH::InvalidateGlobalScopePolluter(cx, obj)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// We're reusing the inner window, but this still counts as a navigation,
|
||||
@ -2499,22 +2496,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
||||
// Add an extra ref in case we release mContext during GC.
|
||||
nsCOMPtr<nsIScriptContext> kungFuDeathGrip(mContext);
|
||||
|
||||
// Now that the prototype is all set up, install the global scope
|
||||
// polluter. This must happen after the above prototype fixup. If
|
||||
// the GSP was to be installed on the inner window's real
|
||||
// prototype (as it would be if this was done before the prototype
|
||||
// fixup above) we would end up holding the GSP alive (through
|
||||
// XPConnect's internal marking of wrapper prototypes) as long as
|
||||
// the inner window was around, and if the GSP had properties on
|
||||
// it that held an element alive we'd hold the document alive,
|
||||
// which could hold event handlers alive, which hold the context
|
||||
// alive etc.
|
||||
|
||||
if ((!reUseInnerWindow || aDocument != oldDoc) && !aState) {
|
||||
JS::Rooted<JSObject*> obj(cx, newInnerWindow->mJSObject);
|
||||
nsWindowSH::InstallGlobalScopePolluter(cx, obj);
|
||||
}
|
||||
|
||||
aDocument->SetScriptGlobalObject(newInnerWindow);
|
||||
|
||||
if (!aState) {
|
||||
@ -3843,6 +3824,23 @@ nsGlobalWindow::IndexedGetter(uint32_t aIndex, bool& aFound)
|
||||
return windows->IndexedGetter(aIndex, aFound);
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::GetSupportedNames(nsTArray<nsString>& aNames)
|
||||
{
|
||||
FORWARD_TO_OUTER_VOID(GetSupportedNames, (aNames));
|
||||
|
||||
nsDOMWindowList* windows = GetWindowList();
|
||||
if (windows) {
|
||||
uint32_t length = windows->GetLength();
|
||||
nsString* name = aNames.AppendElements(length);
|
||||
for (uint32_t i = 0; i < length; ++i, ++name) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> item =
|
||||
windows->GetDocShellTreeItemAt(i);
|
||||
item->GetName(*name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalWindow::GetApplicationCache(nsIDOMOfflineResourceList **aApplicationCache)
|
||||
{
|
||||
|
@ -470,6 +470,8 @@ public:
|
||||
uint32_t GetLength();
|
||||
already_AddRefed<nsIDOMWindow> IndexedGetter(uint32_t aIndex, bool& aFound);
|
||||
|
||||
void GetSupportedNames(nsTArray<nsString>& aNames);
|
||||
|
||||
// Object Management
|
||||
nsGlobalWindow(nsGlobalWindow *aOuterWindow);
|
||||
|
||||
|
@ -1336,7 +1336,6 @@ GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
|
||||
bool
|
||||
HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
DOMProxyHandler* handler,
|
||||
JS::Handle<jsid> id)
|
||||
{
|
||||
JS::Rooted<JSObject*> obj(cx, proxy);
|
||||
@ -1345,11 +1344,38 @@ HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
obj = js::UncheckedUnwrap(obj);
|
||||
ac.construct(cx, obj);
|
||||
}
|
||||
MOZ_ASSERT(js::IsProxy(obj) && js::GetProxyHandler(obj) == handler);
|
||||
|
||||
bool found;
|
||||
// We ignore an error from GetPropertyOnPrototype.
|
||||
return !GetPropertyOnPrototype(cx, obj, id, &found, NULL) || found;
|
||||
// We ignore an error from GetPropertyOnPrototype. We pass nullptr
|
||||
// for vp so that GetPropertyOnPrototype won't actually do a get.
|
||||
return !GetPropertyOnPrototype(cx, obj, id, &found, nullptr) || found;
|
||||
}
|
||||
|
||||
bool
|
||||
AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
nsTArray<nsString>& names,
|
||||
bool shadowPrototypeProperties,
|
||||
JS::AutoIdVector& props)
|
||||
{
|
||||
for (uint32_t i = 0; i < names.Length(); ++i) {
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
if (!xpc::NonVoidStringToJsval(cx, names[i], v.address())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<jsid> id(cx);
|
||||
if (!JS_ValueToId(cx, v, id.address())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (shadowPrototypeProperties || !HasPropertyOnPrototype(cx, proxy, id)) {
|
||||
if (!props.append(id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
|
@ -1417,6 +1417,8 @@ WantsQueryInterface<T, true>
|
||||
bool
|
||||
ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
// vp is allowed to be null; in that case no get will be attempted,
|
||||
// and *found will simply indicate whether the property exists.
|
||||
bool
|
||||
GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::Handle<jsid> id, bool* found,
|
||||
@ -1424,9 +1426,18 @@ GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
|
||||
bool
|
||||
HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
DOMProxyHandler* handler,
|
||||
JS::Handle<jsid> id);
|
||||
|
||||
|
||||
// Append the property names in "names" to "props". If
|
||||
// shadowPrototypeProperties is false then skip properties that are also
|
||||
// present on the proto chain of proxy. If shadowPrototypeProperties is true,
|
||||
// then the "proxy" argument is ignored.
|
||||
bool
|
||||
AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
nsTArray<nsString>& names,
|
||||
bool shadowPrototypeProperties, JS::AutoIdVector& props);
|
||||
|
||||
template<class T>
|
||||
class OwningNonNull
|
||||
{
|
||||
|
@ -6981,7 +6981,7 @@ class CGEnumerateOwnPropertiesViaGetOwnPropertyNames(CGAbstractBindingMethod):
|
||||
"}\n"
|
||||
'// OK to pass null as "proxy" because it\'s ignored if\n'
|
||||
"// shadowPrototypeProperties is true\n"
|
||||
"return DOMProxyHandler::AppendNamedPropertyIds(cx, JS::NullPtr(), names, true, nullptr, props);"))
|
||||
"return AppendNamedPropertyIds(cx, JS::NullPtr(), names, true, props);"))
|
||||
|
||||
class CGPrototypeTraitsClass(CGClass):
|
||||
def __init__(self, descriptor, indent=''):
|
||||
@ -7343,7 +7343,7 @@ MOZ_ASSERT_IF(desc.object(), desc.object() == ${holder});"""
|
||||
fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;" % readonly
|
||||
templateValues = {'jsvalRef': 'desc.value()', 'jsvalHandle': 'desc.value()',
|
||||
'obj': 'proxy', 'successCode': fillDescriptor}
|
||||
condition = "!HasPropertyOnPrototype(cx, proxy, this, id)"
|
||||
condition = "!HasPropertyOnPrototype(cx, proxy, id)"
|
||||
if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
|
||||
condition = "(!isXray || %s)" % condition
|
||||
condition = "!(flags & JSRESOLVE_ASSIGNING) && " + condition
|
||||
@ -7514,7 +7514,7 @@ class CGDOMJSProxyHandler_delete(ClassMethod):
|
||||
"}\n")
|
||||
if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
|
||||
delete = CGIfWrapper(CGGeneric(delete),
|
||||
"!HasPropertyOnPrototype(cx, proxy, this, id)").define()
|
||||
"!HasPropertyOnPrototype(cx, proxy, id)").define()
|
||||
delete += """
|
||||
|
||||
return dom::DOMProxyHandler::delete_(cx, proxy, id, bp);"""
|
||||
@ -7551,7 +7551,7 @@ for (int32_t i = 0; i < int32_t(length); ++i) {
|
||||
addNames = """
|
||||
nsTArray<nsString> names;
|
||||
UnwrapProxy(proxy)->GetSupportedNames(names);
|
||||
if (!AppendNamedPropertyIds(cx, proxy, names, %s, this, props)) {
|
||||
if (!AppendNamedPropertyIds(cx, proxy, names, %s, props)) {
|
||||
return false;
|
||||
}
|
||||
""" % shadow
|
||||
@ -7615,7 +7615,7 @@ class CGDOMJSProxyHandler_hasOwn(ClassMethod):
|
||||
"*bp = found;\n")
|
||||
if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
|
||||
named = CGIfWrapper(CGGeneric(named + "return true;\n"),
|
||||
"!HasPropertyOnPrototype(cx, proxy, this, id)").define()
|
||||
"!HasPropertyOnPrototype(cx, proxy, id)").define()
|
||||
named += ("\n"
|
||||
"*bp = false;")
|
||||
else:
|
||||
|
@ -160,8 +160,11 @@ DOMProxyHandler::preventExtensions(JSContext *cx, JS::Handle<JSObject*> proxy)
|
||||
}
|
||||
|
||||
bool
|
||||
DOMProxyHandler::getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
|
||||
MutableHandle<JSPropertyDescriptor> desc, unsigned flags)
|
||||
BaseDOMProxyHandler::getPropertyDescriptor(JSContext* cx,
|
||||
JS::Handle<JSObject*> proxy,
|
||||
JS::Handle<jsid> id,
|
||||
MutableHandle<JSPropertyDescriptor> desc,
|
||||
unsigned flags)
|
||||
{
|
||||
if (!getOwnPropertyDescriptor(cx, proxy, id, desc, flags)) {
|
||||
return false;
|
||||
@ -221,7 +224,8 @@ DOMProxyHandler::delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
}
|
||||
|
||||
bool
|
||||
DOMProxyHandler::enumerate(JSContext* cx, JS::Handle<JSObject*> proxy, AutoIdVector& props)
|
||||
BaseDOMProxyHandler::enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
AutoIdVector& props)
|
||||
{
|
||||
JS::Rooted<JSObject*> proto(cx);
|
||||
if (!JS_GetPrototype(cx, proxy, &proto)) {
|
||||
@ -260,37 +264,6 @@ DOMProxyHandler::has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid
|
||||
return ok;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
DOMProxyHandler::AppendNamedPropertyIds(JSContext* cx,
|
||||
JS::Handle<JSObject*> proxy,
|
||||
nsTArray<nsString>& names,
|
||||
bool shadowPrototypeProperties,
|
||||
DOMProxyHandler* handler,
|
||||
JS::AutoIdVector& props)
|
||||
{
|
||||
for (uint32_t i = 0; i < names.Length(); ++i) {
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
if (!xpc::NonVoidStringToJsval(cx, names[i], v.address())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<jsid> id(cx);
|
||||
if (!JS_ValueToId(cx, v, id.address())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (shadowPrototypeProperties ||
|
||||
!HasPropertyOnPrototype(cx, proxy, handler, id)) {
|
||||
if (!props.append(id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t
|
||||
IdToInt32(JSContext* cx, JS::Handle<jsid> id)
|
||||
{
|
||||
|
@ -27,18 +27,33 @@ enum {
|
||||
|
||||
template<typename T> struct Prefable;
|
||||
|
||||
class DOMProxyHandler : public js::BaseProxyHandler
|
||||
class BaseDOMProxyHandler : public js::BaseProxyHandler
|
||||
{
|
||||
public:
|
||||
BaseDOMProxyHandler(void* aProxyFamily)
|
||||
: js::BaseProxyHandler(aProxyFamily)
|
||||
{}
|
||||
|
||||
// Implementations of traps that can be implemented in terms of
|
||||
// fundamental traps.
|
||||
bool enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::AutoIdVector& props) MOZ_OVERRIDE;
|
||||
bool getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JSPropertyDescriptor> desc,
|
||||
unsigned flags) MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
class DOMProxyHandler : public BaseDOMProxyHandler
|
||||
{
|
||||
public:
|
||||
DOMProxyHandler(const DOMClass& aClass)
|
||||
: js::BaseProxyHandler(ProxyFamily()),
|
||||
: BaseDOMProxyHandler(ProxyFamily()),
|
||||
mClass(aClass)
|
||||
{
|
||||
}
|
||||
|
||||
bool preventExtensions(JSContext *cx, JS::Handle<JSObject*> proxy) MOZ_OVERRIDE;
|
||||
bool getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JSPropertyDescriptor> desc, unsigned flags) MOZ_OVERRIDE;
|
||||
bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE
|
||||
{
|
||||
@ -49,7 +64,6 @@ public:
|
||||
JS::MutableHandle<JSPropertyDescriptor> desc, bool* defined);
|
||||
bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
JS::Handle<jsid> id, bool* bp) MOZ_OVERRIDE;
|
||||
bool enumerate(JSContext* cx, JS::Handle<JSObject*> proxy, JS::AutoIdVector& props) MOZ_OVERRIDE;
|
||||
bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, bool* bp) MOZ_OVERRIDE;
|
||||
bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible) MOZ_OVERRIDE;
|
||||
|
||||
@ -76,16 +90,6 @@ public:
|
||||
JS::Handle<JSObject*> obj);
|
||||
|
||||
const DOMClass& mClass;
|
||||
|
||||
// Append the property names in "names" to "props". If
|
||||
// shadowPrototypeProperties is false then skip properties that are also
|
||||
// present on our proto chain. If shadowPrototypeProperties is true,
|
||||
// then the "proxy" and "handler" arguments are ignored.
|
||||
static bool AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
nsTArray<nsString>& names,
|
||||
bool shadowPrototypeProperties,
|
||||
DOMProxyHandler* handler,
|
||||
JS::AutoIdVector& props);
|
||||
};
|
||||
|
||||
extern jsid s_length_id;
|
||||
|
@ -45,3 +45,4 @@ MSG_DEF(MSG_INVALID_BYTESTRING, 2, "Cannot convert string to ByteString because
|
||||
" at index {0} has value {1} which is greater than 255.")
|
||||
MSG_DEF(MSG_NOT_DATE, 1, "{0} is not a date.")
|
||||
MSG_DEF(MSG_INVALID_ADVANCE_COUNT, 0, "0 (Zero) is not a valid advance count.")
|
||||
MSG_DEF(MSG_DEFINEPROPERTY_ON_GSP, 0, "Not allowed to define a property on the named properties object.")
|
||||
|
@ -1,5 +1,4 @@
|
||||
{
|
||||
"Static name on the prototype": true,
|
||||
"constructor": true,
|
||||
"Ghost name": true
|
||||
"constructor": true
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
{
|
||||
"Window.prototype": true,
|
||||
"Global scope polluter": true,
|
||||
"EventTarget.prototype": true,
|
||||
"Object.prototype": true
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user