Fixing bug 150824. Don't crash if initialization of an XBL JS class fails. r=dbradley@netscape.com, sr=alecf@netscape.com

This commit is contained in:
jst%netscape.com 2002-06-21 20:55:17 +00:00
parent c55741b7c5
commit 220258d498
4 changed files with 81 additions and 126 deletions

View File

@ -125,7 +125,7 @@ XBLFinalize(JSContext *cx, JSObject *obj)
c->Drop();
}
nsXBLJSClass::nsXBLJSClass(const nsCString& aClassName)
nsXBLJSClass::nsXBLJSClass(const nsAFlatCString& aClassName)
{
memset(this, 0, sizeof(nsXBLJSClass));
next = prev = NS_STATIC_CAST(JSCList*, this);
@ -1229,42 +1229,18 @@ nsXBLBinding::AttributeAffectsStyle(nsISupportsArrayEnumFunc aFunc, void* aData,
// Internal helper methods ////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsXBLBinding::InitClass(const nsCString& aClassName, nsIScriptContext* aContext,
nsIDocument* aDocument, void** aScriptObject, void** aClassObject)
// static
nsresult
nsXBLBinding::DoInitJSClass(JSContext *cx, JSObject *global, JSObject *obj,
const nsAFlatCString& aClassName,
void **aClassObject)
{
*aClassObject = nsnull;
*aScriptObject = nsnull;
nsresult rv;
// Obtain the bound element's current script object.
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
NS_ENSURE_SUCCESS(rv, rv);
JSContext* jscontext = (JSContext*)aContext->GetNativeContext();
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
JSObject* global = ::JS_GetGlobalObject(jscontext);
rv = xpc->WrapNative(jscontext, global, mBoundElement,
NS_GET_IID(nsISupports), getter_AddRefs(wrapper));
NS_ENSURE_SUCCESS(rv, rv);
JSObject* object = nsnull;
rv = wrapper->GetJSObject(&object);
NS_ENSURE_SUCCESS(rv, rv);
*aScriptObject = object;
// First ensure our JS class is initialized.
jsval vp;
jsval val;
JSObject* proto;
if ((! ::JS_LookupProperty(jscontext, global, aClassName.get(), &vp)) ||
JSVAL_IS_PRIMITIVE(vp)) {
if ((!::JS_LookupProperty(cx, global, aClassName.get(), &val)) ||
JSVAL_IS_PRIMITIVE(val)) {
// We need to initialize the class.
nsXBLJSClass* c;
@ -1285,6 +1261,7 @@ nsXBLBinding::InitClass(const nsCString& aClassName, nsIScriptContext* aContext,
if (JS_CLIST_IS_EMPTY(&nsXBLService::gClassLRUList)) {
// We need to create a struct for this class.
c = new nsXBLJSClass(aClassName);
if (!c)
return NS_ERROR_OUT_OF_MEMORY;
} else {
@ -1306,41 +1283,88 @@ nsXBLBinding::InitClass(const nsCString& aClassName, nsIScriptContext* aContext,
// Add c to our table.
(nsXBLService::gClassTable)->Put(&key, (void*)c);
}
// Retrieve the current prototype of the JS object.
JSObject* parent_proto = ::JS_GetPrototype(jscontext, object);
// Retrieve the current prototype of obj.
JSObject* parent_proto = ::JS_GetPrototype(cx, obj);
// The prototype holds a strong reference to its class struct.
c->Hold();
// Make a new object prototyped by parent_proto and parented by global.
proto = ::JS_InitClass(jscontext, // context
proto = ::JS_InitClass(cx, // context
global, // global object
parent_proto, // parent proto
c, // JSClass
NULL, // JSNative ctor
nsnull, // JSNative ctor
0, // ctor args
nsnull, // proto props
nsnull, // proto funcs
nsnull, // ctor props (static)
nsnull); // ctor funcs (static)
if (!proto) {
// This will happen if we're OOM or if the security manager
// denies defining the new class...
(nsXBLService::gClassTable)->Remove(&key);
delete c;
c->Drop();
return NS_ERROR_OUT_OF_MEMORY;
}
// The prototype holds a strong reference to its class struct.
c->Hold();
*aClassObject = (void*)proto;
}
else {
proto = JSVAL_TO_OBJECT(vp);
proto = JSVAL_TO_OBJECT(val);
}
// Set the prototype of our object to be the new class.
::JS_SetPrototype(jscontext, object, proto);
if (!::JS_SetPrototype(cx, obj, proto)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
nsXBLBinding::InitClass(const nsCString& aClassName,
nsIScriptContext* aContext,
nsIDocument* aDocument, void** aScriptObject,
void** aClassObject)
{
*aClassObject = nsnull;
*aScriptObject = nsnull;
nsresult rv;
// Obtain the bound element's current script object.
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
NS_ENSURE_SUCCESS(rv, rv);
JSContext* cx = (JSContext*)aContext->GetNativeContext();
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
JSObject* global = ::JS_GetGlobalObject(cx);
rv = xpc->WrapNative(cx, global, mBoundElement, NS_GET_IID(nsISupports),
getter_AddRefs(wrapper));
NS_ENSURE_SUCCESS(rv, rv);
JSObject* object = nsnull;
rv = wrapper->GetJSObject(&object);
NS_ENSURE_SUCCESS(rv, rv);
*aScriptObject = object;
// First ensure our JS class is initialized.
rv = DoInitJSClass(cx, global, object, aClassName, aClassObject);
NS_ENSURE_SUCCESS(rv, rv);
// Root mBoundElement so that it doesn't loose it's binding
nsCOMPtr<nsIDocument> doc;
mBoundElement->GetDocument(*getter_AddRefs(doc));
if (doc) {

View File

@ -50,6 +50,7 @@ class nsSupportsHashtable;
class nsIXBLService;
class nsFixedSizeAllocator;
class nsXBLEventHandler;
struct JSContext;
// *********************************************************************/
// The XBLBinding class
@ -131,7 +132,11 @@ public:
void InstallAnonymousContent(nsIContent* aAnonParent, nsIContent* aElement);
static nsresult GetTextData(nsIContent *aParent, nsString& aResult);
static nsresult DoInitJSClass(JSContext *cx, JSObject *global, JSObject *obj,
const nsAFlatCString& aClassName,
void **aClassObject);
// Static members
static PRUint32 gRefCnt;

View File

@ -865,93 +865,19 @@ nsXBLPrototypeBinding::GetImmediateChild(nsIAtom* aTag, nsIContent** aResult)
}
NS_IMETHODIMP
nsXBLPrototypeBinding::InitClass(const nsCString& aClassName, nsIScriptContext * aContext, void * aScriptObject, void ** aClassObject)
nsXBLPrototypeBinding::InitClass(const nsCString& aClassName,
nsIScriptContext * aContext,
void * aScriptObject, void ** aClassObject)
{
NS_ENSURE_ARG_POINTER (aClassObject);
*aClassObject = nsnull;
JSContext* jscontext = (JSContext*)aContext->GetNativeContext();
JSObject* global = ::JS_GetGlobalObject(jscontext);
JSContext* cx = (JSContext*)aContext->GetNativeContext();
JSObject* scriptObject = (JSObject*) aScriptObject;
// First ensure our JS class is initialized.
jsval vp;
JSObject* proto;
if ((! ::JS_LookupProperty(jscontext, global, aClassName.get(), &vp)) || JSVAL_IS_PRIMITIVE(vp)) {
// We need to initialize the class.
nsXBLJSClass* c;
void* classObject;
nsCStringKey key(aClassName);
classObject = (nsXBLService::gClassTable)->Get(&key);
if (classObject) {
c = NS_STATIC_CAST(nsXBLJSClass*, classObject);
// If c is on the LRU list (i.e., not linked to itself), remove it now!
JSCList* link = NS_STATIC_CAST(JSCList*, c);
if (c->next != link) {
JS_REMOVE_AND_INIT_LINK(link);
nsXBLService::gClassLRUListLength--;
}
}
else {
if (JS_CLIST_IS_EMPTY(&nsXBLService::gClassLRUList)) {
// We need to create a struct for this class.
c = new nsXBLJSClass(aClassName);
if (!c)
return NS_ERROR_OUT_OF_MEMORY;
}
else {
// Pull the least recently used class struct off the list.
JSCList* lru = (nsXBLService::gClassLRUList).next;
JS_REMOVE_AND_INIT_LINK(lru);
nsXBLService::gClassLRUListLength--;
// Remove any mapping from the old name to the class struct.
c = NS_STATIC_CAST(nsXBLJSClass*, lru);
nsCStringKey oldKey(c->name);
(nsXBLService::gClassTable)->Remove(&oldKey);
// Change the class name and we're done.
nsMemory::Free((void*) c->name);
c->name = ToNewCString(aClassName);
}
// Add c to our table.
(nsXBLService::gClassTable)->Put(&key, (void*)c);
}
// Retrieve the current prototype of the JS object.
JSObject* parent_proto = ::JS_GetPrototype(jscontext, scriptObject);
// Make a new object prototyped by parent_proto and parented by global.
proto = ::JS_InitClass(jscontext, // context
global, // global object
parent_proto, // parent proto
c, // JSClass
NULL, // JSNative ctor
0, // ctor args
nsnull, // proto props
nsnull, // proto funcs
nsnull, // ctor props (static)
nsnull); // ctor funcs (static)
if (!proto) {
(nsXBLService::gClassTable)->Remove(&key);
delete c;
return NS_ERROR_OUT_OF_MEMORY;
}
// The prototype holds a strong reference to its class struct.
c->Hold();
*aClassObject = (void *) proto;
}
else
proto = JSVAL_TO_OBJECT(vp);
::JS_SetPrototype(jscontext, scriptObject, proto);
return NS_OK;
return nsXBLBinding::DoInitJSClass(cx, ::JS_GetGlobalObject(cx),
scriptObject, aClassName, aClassObject);
}
void

View File

@ -148,7 +148,7 @@ private:
nsrefcnt Destroy();
public:
nsXBLJSClass(const nsCString& aClassName);
nsXBLJSClass(const nsAFlatCString& aClassName);
~nsXBLJSClass() { nsMemory::Free((void*) name); }
nsrefcnt Hold() { return ++mRefCnt; }