Closed Bug 293386 Opened 20 years ago Closed 19 years ago

Audit UnbindFromTree codepaths to make sure teardown change is OK

Categories

(Core :: DOM: Navigation, defect)

x86
Linux
defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla1.8beta4

People

(Reporter: bzbarsky, Assigned: bryner)

References

Details

(Keywords: fixed1.8, Whiteboard: [no l10n impact])

Attachments

(3 files)

I should have realized this in bug 274784. Might have prevented the session history regression.... :( In any case, SetScriptGlobalObject had this comment: // XXX HACK ALERT! If the script context owner is null, the document // will soon be going away. So tell our content that to lose its // reference to the document. This has to be done before we actually // set the script context owner to null so that the content elements // can remove references to their script objects. My review comments said something about removing the comment if it's not relevant... That was a major mistake. Either we need to be sure that it's not relevant, or we need to restore this code in the preffed-off case. Some things that should especially bear watching (other than the aforementioned form state saving) when doing this audit: 1) XBL binding teardown 2) XUL element UnbindFromTree (controllers, event listeners, lots of fun here) Fwiw, I bet the leak we saw was in fact through the controllers. Do we have a bug on that? In any case, we really need to do this if we're going to have a hope of the "regression free" aspect of "preffed off".
This should probably block b2 or b3.....
Flags: blocking1.8b2?
Flags: blocking-aviary1.1?
bryner will look at for b3.
Flags: blocking1.8b3+
Flags: blocking1.8b2?
Flags: blocking1.8b2-
Flags: blocking1.8b3+ → blocking1.8b3-
I really think this should be done for any release that enables bfcache by default, but if drivers are absolutely sure they want to rescind the blocking+, it'd be nice to at least set the blocking? request for b4....
Flags: blocking1.8b4?
We should audit for b4, and we're gonna test in b3. /be
Flags: blocking1.8b4?
Flags: blocking1.8b4+
Flags: blocking-aviary1.1?
Flags: blocking-aviary1.1+
Whiteboard: [no l10n impact]
Target Milestone: --- → mozilla1.8beta4
Flags: blocking1.8b5+
Flags: blocking1.8b5+
I came up with a couple more while looking at all of the UnbindFromTree implementations: 3) Frame elements destroy their FrameLoader in UnbindFromTree, and it may not be able to get at the domwindow to call SetFrameElementInternal, or at the docshell to call Destroy(). 4) XTF dispatches change notifications for the parent and document from UnbindFromTree, and listeners for those notifications may not be able to access the DOMWindow / docshell either. I didn't come up with anything else really... the other HTML and SVG element impls look ok.
Flags: blocking-aviary1.5+
Ok, here's my analysis so far: 1) xbl binding teardown The main thing that won't happen is that we won't unhook the bound element's prototype from the prototype chain at document teardown. As a testcase, I tried holding a reference to a bound element in an iframe from the parent document, changing the iframe src, then accessing an XBL-defined <property>. In both trunk and Firefox 1.0, the value from the property's getter is returned. So this seems to mean that either the prototype has never been unhooked correctly, or that I'm misunderstanding when the code path in question is triggered. 2) xul element teardown There's a comment that mentions a reference cycle with controller objects implemented in Javascript. I couldn't find any such objects in our tree (lxr'd for Components.interfaces.nsIController), but even if they exist, the cycle mentioned has already been broken by the call to SetNewDocument(null) on the window. 3) frame element teardown Made a simple testcase where a reference to a nested iframe contentwindow is obtained in the outermost document, then the outer iframe is navigated to a new url. Tested what was returned by .frameElement at that point, and got null, but it's because we're hitting the case in nsGlobalWindow::GetFrameElement where the docshell has no parent. The window itself still has mFrameElement pointing to the old frame element, which I think is incorrect. There are some callers who use GetFrameElementInternal directly that could start accessing that element. Also, nsDocShell::Destroy is no longer called from nsFrameLoader::Destroy. This is ok in the simple case because the docshell's last reference is released and Destroy is called from the destructor. However, if someone kept a reference to the docshell, I think it would incorrectly exist in a non-destroyed state. 4) XTF element teardown The main issue here is whether XTFElement implementations will be able to access the window and docshell when ParentChanged and DocumentChanged are called at teardown. My feeling is that we should just document that these objects may not be available, and check all of the in-tree implementations to make sure they handle this correctly. The other thing we might consider is adding a pre-teardown notification before any of this happens. So, to proceed: #1/2: Boris, do you think this assessment makes sense? If so, it seems like we don't need to worry too much about these. #3: I'll attempt a fix to maintain the teardown sequence #4: I'll check the in-tree XTF implementations (which I think is just XForms), and see how it looks.
> 1) xbl binding teardown Hmm... That's odd. We pretty definitely define the property getter and setter on the proto here. And using JSPROP_SHARED, so there should be no slots on the object itself. Brendan, any idea what's up here? > 2) xul element teardown As long as we're not leaking, all's good here.
So, for issue #3, maybe I've forgotten what I was concerned about or maybe something has changed in the last couple of weeks, but I can't reproduce the problem now where the docshell is not destroyed and the frame element is not nulled out. The FrameLoader holds its own reference to the docshell, so it doesn't depend on the document's ScriptGlobalObject to get ahold of it.
For issue #4, there's a problem with the way XForms currently does its model-destruct events. It does them via XTF's DocumentChange notification, which happens when UnbindFromTree is called... after the document has been detached from the window. That means that an event listener on the window won't be able to listen for these events. Given the way this event is defined to work, I think the most straightforward solution is to have XForms listen for unload and dispatch this event from there, when the window is still intact. This will have the effect of disabling fastback for documents containing XForms content. If that's no good, another solution would be to add the unload listener only if model-destruct listeners exist, but that could be quite involved. In any case, I'm not going to have time to make that change to XForms, so cc'ing doron and aaron. I think the semantics of the XTF notifications are probably still ok, just with the caveat that the window is inaccessible at document teardown. XTF implementations that need to deal with pagehide/unload can set up their own listeners for that... quite a bit cleaner IMO than dispatching some notification to every XTFElement in the document.
Attached file xbl testcase
So, if you load attachment 197215 [details] and click "navigate" then "check property", I think this should test whether the prototype is still hooked up to the element. If you see "2", then it is. Given the teardown code, I'd think it would come back undefined, but I do indeed get "2", both on the trunk and in ff 1.0.x.
Oh, wow. It looks like prototype unhooking has actually been broken ever since XBL stopped creating elements for most things... :( There's never going to be an immediate child of the proto binding called "implementation" in our current setup. This should be checking whether the proto has a non-null mImplementation object instead...
I filed bug 310109 for the XForms problem, and bug 310107 for the XBL prototype unhooking problem. Closing this bug since we finished investigating the change.
Status: NEW → RESOLVED
Closed: 19 years ago
Resolution: --- → FIXED
Keywords: fixed1.8
Component: History: Session → Document Navigation
QA Contact: history.session → docshell
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: