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)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla1.9.1b2

People

(Reporter: bent.mozilla, Assigned: mozilla+ben)

References

Details

Attachments

(2 files, 3 obsolete files)

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?
Attached patch proposed patch (obsolete) — Splinter Review
Replaced the XPCVariant with an nsAutoJSValHolder, which is a slightly more general replacement for bent's nsAutoJSObjectHolder.
Attachment #345810 - Flags: review?(bent.mozilla)
Attachment #345810 - Flags: superreview?(jst)
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.
Attached patch implementing bent's suggestions (obsolete) — Splinter Review
(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)
Attachment #346053 - Flags: review?(bent.mozilla)
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.
(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)
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+
Attachment #346086 - Flags: superreview?(jst) → superreview+
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
(In reply to comment #7) > Pushed to moz-central. For future reference: <http://hg.mozilla.org/mozilla-central/rev/6004a7f6e478>
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 !
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.
We should remove the JSObject* operator in favor of the jsval operator.
Probably a good policy to avoid having more than one conversion operator per class.
Attachment #347599 - Flags: review?(bent.mozilla)
Attachment #347599 - Attachment is patch: true
Attachment #347599 - Attachment mime type: application/octet-stream → text/plain
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+
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 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+
(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?
(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 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)
Attachment #347627 - Flags: superreview+
Add checkin-needed for the last patch.
Keywords: checkin-needed
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 on attachment 347627 [details] [diff] [review] NULL instead of JS_NULL a1.9.1b2=beltzner
Attachment #347627 - Flags: approval1.9.1b2? → approval1.9.1b2+
Depends on: 467865
Depends on: 467900
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.

Attachment

General

Created:
Updated:
Size: