Closed Bug 1087799 Opened 11 years ago Closed 11 years ago

Handle cycle collector reentrance better

Categories

(Core :: XPCOM, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla36

People

(Reporter: mccr8, Assigned: mccr8)

References

Details

(Keywords: sec-audit)

Attachments

(3 files)

For some reason, this has started happening a lot on TBPL, but the stack looks familiar. What appears to be happening is this: - We're in the middle of an incremental CC. - We decide to GC. -- Thus, we need to finish the incremental CC. Eventually, run Unlink(). --- This runs Promise::cycleCollection::Unlink(), which runs random JS. ---- This triggers a new GC. ----- We're still in the middle of an ICC, so finish the current ICC. ------ We detect reentrance, so we return immediately. ------ The assertion fires because we have not finished the CC. I think this is sort of okay right now, because we never touch JS in Unlink, but it is kind of getting into a sketchier situation with bug 1052793, because then we store pointers to zones. Though maybe if we're careful that will be okay... I'm not quite sure of the security implications, so I'm hiding it for now.
One possible safer solution would be to have the CC root |whiteNodes|, and implement some kind of trace hook that scans everything looking for JS. It would be a little slow, but hopefully this isn't too common. I'm not really sure how that would work for entire JS zones, but I guess we could root all globals in the zone, because that's all we really look at.
Assignee: nobody → continuation
>--- This runs Promise::cycleCollection::Unlink(), which runs random JS. Note that we're working on stopping that insanity.
(In reply to Boris Zbarsky [:bz] from comment #2) > Note that we're working on stopping that insanity. Being able to just ban GC entirely during Unlink() would make Terrence happy. :)
I looked at this, and I'm pretty sure we're not touching GC objects after we might GC. However, there are some improvements we can make to enforce this more thoroughly.
Group: core-security
If an Unlink() method ends up running JS, it can cause a GC, which will make us reenter the CC, which will not do anything because we're already in a CC. Therefore, FinishAnyCurrentCollection() won't finish the CC. This is safe because the CC only touches things it actually holds alive via the Root() method.
Attachment #8511296 - Flags: review?(bugs)
Root() does not actually root JS things, so if some other class's Unlink() method ends up calling the GC, whiteNodes will end up containing dead pointers. (This is safe right now because the Unlink and Unroot methods do not do anything to JS things.) It is less error prone to simply never store those pointers. Also, add some asserts to enforce that we never call any of the white-object methods for JS things.
Attachment #8511298 - Flags: review?(bugs)
try run: https://tbpl.mozilla.org/?tree=Try&rev=571af010f313 This try run had a stricter version that nulled out mPointers for things in the graph that we didn't add to whiteNodes, but that seems like overkill.
(In reply to Kyle Huey [:khuey] (khuey@mozilla.com) from comment #9) > Should probably dupe bug 1062012 forward. Ah, thanks, I knew there was another bug floating around somewhere.
Comment on attachment 8511296 [details] [diff] [review] part 1 - Loosen the invariant in nsCycleCollector::FinishAnyCurrentCollection(). A bit odd setup, but should work.
Attachment #8511296 - Flags: review?(bugs) → review+
Attachment #8511297 - Flags: review?(bugs) → review+
Comment on attachment 8511298 [details] [diff] [review] part 3 - Do not include any JS things in the list of white nodes. Oh, this should speed up unlink a bit.
Attachment #8511298 - Flags: review?(bugs) → review+
(In reply to Olli Pettay [:smaug] from comment #13) > Oh, this should speed up unlink a bit. You'd think so, but when I tried this before I couldn't measure any speedup.
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: