Prevent circular ownership leaks via XPCOM-JS cycles through treewalker's filter, the same way we do for event listeners. b=323534 r=mrbkap sr=jst

git-svn-id: svn://10.0.0.236/trunk@187810 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
dbaron%dbaron.org 2006-01-19 02:46:18 +00:00
parent 934879ff1e
commit 6af4529cc1
5 changed files with 89 additions and 30 deletions

View File

@ -84,11 +84,11 @@ nsTreeWalker::nsTreeWalker(nsIDOMNode *aRoot,
PRBool aExpandEntityReferences) :
mRoot(aRoot),
mWhatToShow(aWhatToShow),
mFilter(aFilter),
mExpandEntityReferences(aExpandEntityReferences),
mCurrentNode(aRoot),
mPossibleIndexesPos(-1)
{
mFilter.Set(aFilter, this);
NS_ASSERTION(aRoot, "invalid root in call to nsTreeWalker constructor");
}
@ -105,7 +105,8 @@ nsTreeWalker::~nsTreeWalker()
// QueryInterface implementation for nsTreeWalker
NS_INTERFACE_MAP_BEGIN(nsTreeWalker)
NS_INTERFACE_MAP_ENTRY(nsIDOMTreeWalker)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMTreeWalker)
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(TreeWalker)
NS_INTERFACE_MAP_END
@ -136,8 +137,10 @@ NS_IMETHODIMP nsTreeWalker::GetWhatToShow(PRUint32 *aWhatToShow)
NS_IMETHODIMP nsTreeWalker::GetFilter(nsIDOMNodeFilter * *aFilter)
{
NS_ENSURE_ARG_POINTER(aFilter);
*aFilter = mFilter;
NS_IF_ADDREF(*aFilter);
nsCOMPtr<nsIDOMNodeFilter> filter = mFilter.Get();
filter.swap((*aFilter = nsnull));
return NS_OK;
}
@ -269,6 +272,29 @@ NS_IMETHODIMP nsTreeWalker::NextNode(nsIDOMNode **_retval)
_retval);
}
/*
* nsIDOMGCParticipant functions
*/
/* virtual */ nsIDOMGCParticipant*
nsTreeWalker::GetSCCIndex()
{
return this;
}
/* virtual */ void
nsTreeWalker::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
{
nsCOMPtr<nsIDOMGCParticipant> gcp;
gcp = do_QueryInterface(mRoot);
if (gcp)
aArray.AppendObject(gcp);
gcp = do_QueryInterface(mCurrentNode);
if (gcp)
aArray.AppendObject(gcp);
}
/*
* nsTreeWalker helper functions
*/
@ -594,8 +620,9 @@ nsresult nsTreeWalker::TestNode(nsIDOMNode* aNode, PRInt16* _filtered)
return NS_OK;
}
if (mFilter)
return mFilter->AcceptNode(aNode, _filtered);
nsCOMPtr<nsIDOMNodeFilter> filter = mFilter.Get();
if (filter)
return filter->AcceptNode(aNode, _filtered);
*_filtered = nsIDOMNodeFilter::FILTER_ACCEPT;
return NS_OK;

View File

@ -49,13 +49,19 @@
#include "nsIDOMNodeFilter.h"
#include "nsCOMPtr.h"
#include "nsVoidArray.h"
#include "nsIDOMGCParticipant.h"
#include "nsJSUtils.h"
class nsTreeWalker : public nsIDOMTreeWalker
class nsTreeWalker : public nsIDOMTreeWalker, public nsIDOMGCParticipant
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMTREEWALKER
// nsIDOMGCParticipant
virtual nsIDOMGCParticipant* GetSCCIndex();
virtual void AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray);
nsTreeWalker(nsIDOMNode *aRoot,
PRUint32 aWhatToShow,
nsIDOMNodeFilter *aFilter,
@ -65,7 +71,7 @@ public:
private:
nsCOMPtr<nsIDOMNode> mRoot;
PRUint32 mWhatToShow;
nsCOMPtr<nsIDOMNodeFilter> mFilter;
nsMarkedJSFunctionHolder<nsIDOMNodeFilter> mFilter;
PRBool mExpandEntityReferences;
nsCOMPtr<nsIDOMNode> mCurrentNode;

View File

@ -414,6 +414,11 @@ static const char kDOMStringBundleURL[] =
// NOTE: DEFAULT_SCRIPTABLE_FLAGS and DOM_DEFAULT_SCRIPTABLE_FLAGS
// are defined in nsIDOMClassInfo.h.
#define GCPARTICIPANT_SCRIPTABLE_FLAGS \
(DOM_DEFAULT_SCRIPTABLE_FLAGS | \
nsIXPCScriptable::WANT_FINALIZE | \
nsIXPCScriptable::WANT_MARK)
#define WINDOW_SCRIPTABLE_FLAGS \
(nsIXPCScriptable::WANT_GETPROPERTY | \
nsIXPCScriptable::WANT_SETPROPERTY | \
@ -429,12 +434,10 @@ static const char kDOMStringBundleURL[] =
nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE)
#define NODE_SCRIPTABLE_FLAGS \
((DOM_DEFAULT_SCRIPTABLE_FLAGS | \
((GCPARTICIPANT_SCRIPTABLE_FLAGS | \
nsIXPCScriptable::WANT_PRECREATE | \
nsIXPCScriptable::WANT_ADDPROPERTY | \
nsIXPCScriptable::WANT_SETPROPERTY | \
nsIXPCScriptable::WANT_FINALIZE | \
nsIXPCScriptable::WANT_MARK) & \
nsIXPCScriptable::WANT_SETPROPERTY) & \
~nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY)
// We need to let JavaScript QI elements to interfaces that are not in
@ -815,8 +818,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
DOM_DEFAULT_SCRIPTABLE_FLAGS)
// DOM Traversal classes
NS_DEFINE_CLASSINFO_DATA(TreeWalker, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(TreeWalker, nsDOMGCParticipantSH,
GCPARTICIPANT_SCRIPTABLE_FLAGS)
// We are now trying to preserve binary compat in classinfo. No
// more putting things in those categories up there. New entries
@ -6657,8 +6660,8 @@ nsEventReceiverSH::NewResolve(nsIXPConnectWrappedNative *wrapper,
*objp = obj;
}
return nsDOMClassInfo::NewResolve(wrapper, cx, obj, id, flags, objp,
_retval);
return nsDOMGCParticipantSH::NewResolve(wrapper, cx, obj, id, flags, objp,
_retval);
}
NS_IMETHODIMP
@ -6685,19 +6688,21 @@ nsEventReceiverSH::AddProperty(nsIXPConnectWrappedNative *wrapper,
return nsEventReceiverSH::SetProperty(wrapper, cx, obj, id, vp, _retval);
}
NS_IMETHODIMP
nsEventReceiverSH::Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj)
{
// XXX clear event handlers in mListener...
// XXX nsEventReceiverSH::Finalize: clear event handlers in mListener...
// DOMGCParticipant helper
NS_IMETHODIMP
nsDOMGCParticipantSH::Finalize(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj)
{
nsDOMClassInfo::ReleaseWrapper(wrapper);
return NS_OK;
}
NS_IMETHODIMP
nsEventReceiverSH::Mark(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, void *arg, PRUint32 *_retval)
nsDOMGCParticipantSH::Mark(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, void *arg, PRUint32 *_retval)
{
nsCOMPtr<nsIDOMGCParticipant> participant(do_QueryWrappedNative(wrapper));

View File

@ -370,15 +370,39 @@ protected:
typedef nsDOMClassInfo nsDOMGenericSH;
// Scriptable helper for implementations of nsIDOMGCParticipant that
// need a mark callback.
class nsDOMGCParticipantSH : public nsDOMGenericSH
{
protected:
nsDOMGCParticipantSH(nsDOMClassInfoData* aData) : nsDOMGenericSH(aData)
{
}
virtual ~nsDOMGCParticipantSH()
{
}
public:
NS_IMETHOD Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj);
NS_IMETHOD Mark(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, void *arg, PRUint32 *_retval);
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{
return new nsDOMGCParticipantSH(aData);
}
};
// EventProp scriptable helper, this class should be the base class of
// all objects that should support things like
// obj.onclick=function{...}
class nsEventReceiverSH : public nsDOMGenericSH
class nsEventReceiverSH : public nsDOMGCParticipantSH
{
protected:
nsEventReceiverSH(nsDOMClassInfoData* aData) : nsDOMGenericSH(aData)
nsEventReceiverSH(nsDOMClassInfoData* aData) : nsDOMGCParticipantSH(aData)
{
}
@ -420,10 +444,6 @@ public:
PRBool *_retval);
NS_IMETHOD AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsval id, jsval *vp, PRBool *_retval);
NS_IMETHOD Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj);
NS_IMETHOD Mark(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, void *arg, PRUint32 *_retval);
};

View File

@ -260,7 +260,8 @@ PRBool
nsMarkedJSFunctionHolder_base::TryMarkedSet(nsISupports *aPotentialFunction,
nsIDOMGCParticipant *aParticipant)
{
NS_ENSURE_TRUE(aParticipant, PR_FALSE);
if (!aParticipant)
return PR_FALSE;
nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS =
do_QueryInterface(aPotentialFunction);