Closed
Bug 462389
Opened 17 years ago
Closed 17 years ago
XPCVariant used in nsXPCException::SetThrownJSVal can cause cycle collection on non-main threads
Categories
(Core :: XPConnect, defect)
Core
XPConnect
Tracking
()
RESOLVED
FIXED
mozilla1.9.1b2
People
(Reporter: bent.mozilla, Assigned: mozilla+ben)
References
Details
Attachments
(2 files, 3 obsolete files)
24.05 KB,
patch
|
bent.mozilla
:
review+
jst
:
superreview+
|
Details | Diff | Splinter Review |
3.72 KB,
patch
|
neil
:
review+
jst
:
superreview+
beltzner
:
approval1.9.1b2+
|
Details | Diff | Splinter Review |
XPCVariants are cycle collected yet exceptions can be used from any thread. This means that any non-main thread that runs script that throws an exception can trigger cycle collection off the main thread which will most certainly violate a ton of the collector's assumptions.
Flags: blocking1.9.1?
Assignee | ||
Comment 1•17 years ago
|
||
Replaced the XPCVariant with an nsAutoJSValHolder, which is a slightly more general replacement for bent's nsAutoJSObjectHolder.
Assignee | ||
Updated•17 years ago
|
Attachment #345810 -
Flags: review?(bent.mozilla)
Assignee | ||
Updated•17 years ago
|
Attachment #345810 -
Flags: superreview?(jst)
Reporter | ||
Comment 2•17 years ago
|
||
Comment on attachment 345810 [details] [diff] [review]
proposed patch
>+ (mHeld = JS_AddNamedRootRT(aRt, &mGCThing, "nsAutoRootedJSObject")))
You'll want to change that to nsAutoJSValHolder.
>- mObj = NULL;
>- }
>+ if (mHeld && !(mHeld = !JS_RemoveRootRT(mRt, &mGCThing)))
>+ mRt = NULL;
The old code used to null the object on release to make sure that you didn't hand potentially dangling pointers around. I'd like to keep that.
>+nsXPCException::StealThrownJSVal(jsval *vp)
> {
>+ if(mThrownJSVal.IsHeld()) {
>+ *vp = mThrownJSVal;
>+ mThrownJSVal.Release();
> return PR_TRUE;
> }
> return PR_FALSE;
Hm, maybe Release() should just return the jsval before nulling it, like forget() on nsAutoPtr. What do you think?
>+nsXPCException::StowThrownJSVal(JSContext *cx, jsval v)
> {
>- mThrownJSVal = JSVAL_IS_TRACEABLE(v)
>- ? new XPCTraceableVariant(nsXPConnect::GetRuntimeInstance(), v)
>- : new XPCVariant(v);
>+ mThrownJSVal.Hold(cx);
That can (in theory, maybe not once we have infallible malloc?) fail, and we'd be holding a dangling object if it did. I think you should adjust the signature and check for failure accordingly.
Assignee | ||
Comment 3•17 years ago
|
||
(In reply to comment #2)
> (From update of attachment 345810 [details] [diff] [review])
> >+ (mHeld = JS_AddNamedRootRT(aRt, &mGCThing, "nsAutoRootedJSObject")))
>
> You'll want to change that to nsAutoJSValHolder.
Done.
> >- mObj = NULL;
> >- }
> >+ if (mHeld && !(mHeld = !JS_RemoveRootRT(mRt, &mGCThing)))
> >+ mRt = NULL;
>
> The old code used to null the object on release to make sure that you didn't
> hand potentially dangling pointers around. I'd like to keep that.
No problem. Also nullifying mGCThing, while we're at it.
> >+nsXPCException::StealThrownJSVal(jsval *vp)
> > {
> >+ if(mThrownJSVal.IsHeld()) {
> >+ *vp = mThrownJSVal;
> >+ mThrownJSVal.Release();
> > return PR_TRUE;
> > }
> > return PR_FALSE;
>
> Hm, maybe Release() should just return the jsval before nulling it, like
> forget() on nsAutoPtr. What do you think?
I like that idea.
> >+nsXPCException::StowThrownJSVal(JSContext *cx, jsval v)
> > {
> >- mThrownJSVal = JSVAL_IS_TRACEABLE(v)
> >- ? new XPCTraceableVariant(nsXPConnect::GetRuntimeInstance(), v)
> >- : new XPCVariant(v);
> >+ mThrownJSVal.Hold(cx);
>
> That can (in theory, maybe not once we have infallible malloc?) fail, and we'd
> be holding a dangling object if it did. I think you should adjust the signature
> and check for failure accordingly.
Sure, and calling Release on failure also seems like a good idea.
Thanks for the good ideas, Ben.
Attachment #345810 -
Attachment is obsolete: true
Attachment #345810 -
Flags: superreview?(jst)
Attachment #345810 -
Flags: review?(bent.mozilla)
Assignee | ||
Updated•17 years ago
|
Attachment #346053 -
Flags: review?(bent.mozilla)
Reporter | ||
Comment 4•17 years ago
|
||
Comment on attachment 346053 [details] [diff] [review]
implementing bent's suggestions
>+ nsAutoJSValHolder()
>+ : mRt(NULL)
>+ , mVal(JSVAL_NULL)
>+ , mGCThing(JSVAL_NULL)
This works but it's more correct to set void* to NULL, not JSVAL_NULL. Let's fix that.
> JSBool Hold(JSRuntime* aRt) {
> if (!mHeld) {
>+ if (JS_AddNamedRootRT(aRt, &mGCThing, "nsAutoJSValHolder")) {
> mRt = aRt;
>+ mHeld = JS_TRUE;
>+ } else Release(); // out of memory
This should be on two separate lines, with braces (since the if section needed braces).
>+ jsval Release() {
> NS_ASSERTION(!mHeld || mRt, "Bad!");
>+
>+ jsval oldval = mVal;
>+
>+ if (mHeld)
>+ mHeld = !JS_RemoveRootRT(mRt, &mGCThing);
So I just chatted with mrbkap and JS_RemoveRootRT can't fail... Let's clean this code up in light of that.
>+ if (!mHeld) {
>+ mVal = JSVAL_NULL;
>+ mGCThing = JSVAL_NULL;
NULL.
>+ mGCThing = JSVAL_IS_GCTHING(aOther)
>+ ? JSVAL_TO_GCTHING(aOther)
>+ : JSVAL_NULL;
NULL.
>+ if(mThrownJSVal.IsHeld()) {
>+ *vp = mThrownJSVal.Release();
> return PR_TRUE;
> }
> return PR_FALSE;
Hm, this check would make more sense as 'if(mThrownJSVal)' since you never assign without holding. That way you could always just set *vp = mThrownJSVal.Release() and return true.
Oh, and XPConnect style always has opening braces on the next line.
Assignee | ||
Comment 5•17 years ago
|
||
(In reply to comment #4)
> >+ if(mThrownJSVal.IsHeld()) {
> >+ *vp = mThrownJSVal.Release();
> > return PR_TRUE;
> > }
> > return PR_FALSE;
>
> Hm, this check would make more sense as 'if(mThrownJSVal)' since you never
> assign without holding. That way you could always just set *vp =
> mThrownJSVal.Release() and return true.
Agree with everything except this. Since not all jsvals are objects, mThrownJSVal might evaluate to a NULL JSObject* when we're actually holding a (primitive) jsval.
Otherwise, hope this all looks good.
Attachment #346053 -
Attachment is obsolete: true
Attachment #346086 -
Flags: review?(bent.mozilla)
Attachment #346053 -
Flags: review?(bent.mozilla)
Reporter | ||
Comment 6•17 years ago
|
||
Comment on attachment 346086 [details] [diff] [review]
addressing further comments
Looks great!
Attachment #346086 -
Flags: superreview?(jst)
Attachment #346086 -
Flags: review?(bent.mozilla)
Attachment #346086 -
Flags: review+
Updated•17 years ago
|
Attachment #346086 -
Flags: superreview?(jst) → superreview+
Reporter | ||
Comment 7•17 years ago
|
||
Pushed to moz-central.
Assignee: nobody → bnewman
Status: NEW → RESOLVED
Closed: 17 years ago
Flags: blocking1.9.1?
Resolution: --- → FIXED
Target Milestone: mozilla1.9.1 → mozilla1.9.1b2
Comment 8•17 years ago
|
||
(In reply to comment #7)
> Pushed to moz-central.
For future reference: <http://hg.mozilla.org/mozilla-central/rev/6004a7f6e478>
Comment 9•17 years ago
|
||
Comment on attachment 346086 [details] [diff] [review]
addressing further comments
> /**
> * Pretend to be a JSObject*.
> */
>+ operator JSObject*() const {
>+ return JSVAL_IS_OBJECT(mVal)
>+ ? JSVAL_TO_OBJECT(mVal)
>+ : JSVAL_NULL;
> }
>
> /**
>+ * Pretend to be a jsval.
> */
>+ operator jsval() const { return mVal; }
This confuses VC7.1 because it doesn't know which operator to use for !
Comment 10•17 years ago
|
||
Sun CC is not happy with it either.
"mozilla-central/dom/src/threads/nsDOMWorkerScriptLoader.cpp", line 200: Error: Overloading ambiguity between "nsAutoJSValHolder::operator JSObject*() const" and "nsAutoJSValHolder::operator long() const".
"mozilla-central/dom/src/threads/nsDOMWorkerScriptLoader.cpp", line 204: Error: Overloading ambiguity between "nsAutoJSValHolder::operator JSObject*() const" and "nsAutoJSValHolder::operator long() const".
"mozilla-central/dom/src/threads/nsDOMWorkerScriptLoader.cpp", line 694: Error: Overloading ambiguity between "nsAutoJSValHolder::operator JSObject*() const" and "nsAutoJSValHolder::operator long() const".
"mozilla-central/dom/src/threads/nsDOMWorkerScriptLoader.cpp", line 726: Error: Overloading ambiguity between "nsAutoJSValHolder::operator JSObject*() const" and "nsAutoJSValHolder::operator long() const".
4 Error(s) detected.
Reporter | ||
Comment 11•17 years ago
|
||
We should remove the JSObject* operator in favor of the jsval operator.
Assignee | ||
Comment 12•17 years ago
|
||
Probably a good policy to avoid having more than one conversion operator per class.
Attachment #347599 -
Flags: review?(bent.mozilla)
Assignee | ||
Updated•17 years ago
|
Attachment #347599 -
Attachment is patch: true
Attachment #347599 -
Attachment mime type: application/octet-stream → text/plain
Reporter | ||
Comment 13•17 years ago
|
||
Comment on attachment 347599 [details] [diff] [review]
changed operator JSObject* to a method called ToJSObject
r=me if you change the JSVAL_NULL to NULL :-)
Attachment #347599 -
Flags: review?(bent.mozilla) → review+
Assignee | ||
Comment 14•17 years ago
|
||
Neil and Evan, would you like to sign off on this version?
Attachment #347599 -
Attachment is obsolete: true
Attachment #347627 -
Flags: superreview?(Evan.Yan)
Attachment #347627 -
Flags: review?(neil)
Comment 15•17 years ago
|
||
Comment on attachment 347627 [details] [diff] [review]
NULL instead of JS_NULL
> /**
>- * Pretend to be a JSObject*.
>+ * Explicit JSObject* conversion.
> */
>- operator JSObject*() const {
>+ JSObject* ToJSObject() const {
> return JSVAL_IS_OBJECT(mVal)
> ? JSVAL_TO_OBJECT(mVal)
>- : JSVAL_NULL;
>+ : NULL;
> }
Compiles fine here on VC7.1 but shouldn't that be nsnull instead of NULL?
Attachment #347627 -
Flags: review?(neil) → review+
Assignee | ||
Comment 16•17 years ago
|
||
(In reply to comment #15)
> Compiles fine here on VC7.1 but shouldn't that be nsnull instead of NULL?
I'm inclined to agree. My only reason for using NULL instead of nsnull was that the original nsAutoJSObjectHolder implementation used NULL. Maybe bent (original author) has an opinion on this?
Assignee | ||
Comment 17•17 years ago
|
||
(In reply to comment #16)
> (In reply to comment #15)
> > Compiles fine here on VC7.1 but shouldn't that be nsnull instead of NULL?
>
> I'm inclined to agree. My only reason for using NULL instead of nsnull was
> that the original nsAutoJSObjectHolder implementation used NULL. Maybe bent
> (original author) has an opinion on this?
bent says he did it because the JS engine uses NULL, so I guess it's a moot point. they're all 0, after all.
Comment 18•17 years ago
|
||
Comment on attachment 347627 [details] [diff] [review]
NULL instead of JS_NULL
I'm not a superreviewer, but I can confirm that it makes Sun CC happy. Thanks!
Attachment #347627 -
Flags: superreview?(Evan.Yan)
Updated•17 years ago
|
Attachment #347627 -
Flags: superreview+
Reporter | ||
Comment 21•17 years ago
|
||
Comment on attachment 347627 [details] [diff] [review]
NULL instead of JS_NULL
This trivial patch fixes build bustage for b2 on solaris and windows with vc7.1.
Attachment #347627 -
Flags: approval1.9.1b2?
Comment 22•17 years ago
|
||
Comment on attachment 347627 [details] [diff] [review]
NULL instead of JS_NULL
a1.9.1b2=beltzner
Attachment #347627 -
Flags: approval1.9.1b2? → approval1.9.1b2+
Pushed e67d4de99d98
Keywords: checkin-needed
Comment 24•17 years ago
|
||
this didn't actually fix threadsafety. you're still terribly broken. in addition to doing evil things - bug 467900
You need to log in
before you can comment on or make changes to this bug.
Description
•