Closed Bug 152224 Opened 22 years ago Closed 21 years ago

Leak in nsExternalAppHandler

Categories

(Core Graveyard :: File Handling, defect, P3)

defect

Tracking

(Not tracked)

RESOLVED FIXED
mozilla1.7alpha

People

(Reporter: liffiton, Assigned: Biesinger)

References

(Depends on 1 open bug)

Details

(Keywords: memory-leak)

Attachments

(2 files, 2 obsolete files)

In nsExternalHelperAppService.cpp:

mWebProgressListener is set in SetWebProgressListener() when a new
nsIDownload/nsIWebProgressListener is created, but it is only released in
CloseProgressWindow(), which doesn't seem to be called anywhere.

In my specific case (in a Gecko-embedding environment), this means that download
progress dialogs (which implement nsIDownload and nsIWebProgressListener) are
never released, causing a significant memory leak.
Keywords: mlk
Well... mWebProgressListener is a member variable on a nsExternalAppHandler
object. When said object gets destroyed, the progresslistener is automatically
released.  Is this object not getting destroyed?

CloseProgressWindow() is called by the OnUnload() method in
http://lxr.mozilla.org/seamonkey/source/embedding/components/ui/progressDlg/nsProgressDlg.js;
it does not seem to be called by the download manager anywhere, however...
FYI, I orginally noticed the problem because a breakpoint in my progress
dialog's destructor never triggered.  It just sits around w/ mRefCnt equal to 1.
 I assume this is due to the mWebProgressListener reference, though I may be wrong.

Furthermore, I don't know that I have access to an instance of
nsIHelperAppLauncher to call CloseProgressListener() like in nsProgressDlg.js. 
We used to get it as a parameter to
nsHelperAppLauncherDialog::ShowProgressDialog(), but that method is apparently
obsolete and nothing has replaced it(?).

(Side note:  Is there any documentation for the download API anywhere?  I can
only glean so much by reading the source...)
Blocks: 113007
No longer blocks: 113007
FYI #2:  I've worked around this, though not in a particularly elegant way.  My
class is passed an instance of nsExternalHelperAppService as an nsIObserver in
SetObserver().  I queryinterface this nsIObserver for an nsIHelperAppLauncher
when I need to call CloseProgressWindow() on it.

It would be nice if there were a more proper way to deal with this...
Mark, are you ever seeing the nsExternalAppHandler called in your app?  Both
with and without the workaround you mention in comment 3?

Sorry it's taken me so long to get back to you....

I'm starting to suspect that we may have a reference cycle between the
nsExternalAppHandler and its mWebProgressListener...  that would be bad. ;)
Mark's going to be unavailable for 3 months. I'll see if one of our other 
coders can answer this.
confirming for now and assigning to myself to keep this on my radar.  I will
likely be working on cleaning up these apis some and welcome any feedback or
ideas (in personal email, not in this bug).
Assignee: alecf → bzbarsky
Status: UNCONFIRMED → NEW
Ever confirmed: true
QA Contact: sairuh → petersen
amutch@tln.lib.mi.us?  Mark?  How do things stand here?
Let me check on this and see where we are at.
amutch@tln.lib.mi.us?  Mark?  Any luck?

Marking Future for now due to lack of response....
Priority: -- → P3
Target Milestone: --- → Future
taking. this is a reference cycle:
nsExternalAppHandler has a reference to its listener (must have). as comment 0
mentioned, this is nowhere released (CloseProgressWindow has no caller, not in
seamonkey at least).

listener has a reference to the nsExternalAppHandler, as the nsIObserver to
cancel the download. also nowhere released - again, at least not in seamonkey.
Assignee: bz-vacation → cbiesinger
Target Milestone: Future → mozilla1.7alpha
hm. actually, it looks like there are still 3 references after that... one will
be uriloader, still have to find out what the other two are.
second problem: cycle with mDialog
Attached patch patch (obsolete) — Splinter Review
Status: NEW → ASSIGNED
Comment on attachment 137492 [details] [diff] [review]
patch

so, this does two other things as well:
o Do not use prettyprinting of boolean values, per darin's special request
o send an OnStateChange with STATE_START as well, not only STATE_STOP (required
for download resuming. I can put that into another bug's patch if you prefer)
Attachment #137492 - Flags: review?(bz-vacation)
Comment on attachment 137492 [details] [diff] [review]
patch

in just perusing the patch, I like what I see, but do you want to document
mRequest a little more - i.e. why your'e holding a strong ref to it, and so
forth?
Comment on attachment 137492 [details] [diff] [review]
patch

hm, good point. a weak ref should suffice, given that I don't need it anymore
after OnStopRequest.
Attachment #137492 - Attachment is obsolete: true
Attachment #137492 - Flags: review?(bz-vacation)
Attached patch patch v2 part 1 (obsolete) — Splinter Review
make mRequest a weak reference, clear the reference to mDialog in
CreateProgressListener (because we might need it after OnStopRequest, in
PromptForSaveToFile), also clear it in Cancel.

now... this causes download manager to crash, because it doesn't keep a
reference to the nsDownload objects it puts into its hashtable
(mCurrDownloads). I'll attach a patch for that.
Attachment #137579 - Flags: review?(bz-vacation)
make download manager keep references to the things in its hashtable
Comment on attachment 137580 [details] [diff] [review]
patch v2 part 2 (checked in)

looks good
r=varga
Attachment #137580 - Flags: review?(varga) → review+
Attachment #137580 - Flags: superreview?(darin)
Comment on attachment 137579 [details] [diff] [review]
patch v2 part 1

I won't be able to review this until probably Tuesday.
that's ok, this isn't urgent
Comment on attachment 137580 [details] [diff] [review]
patch v2 part 2 (checked in)

isn't there a hash table that you can use that'll do the addref & release
automagically?

sr=darin
Attachment #137580 - Flags: superreview?(darin) → superreview+
darin: there is, but it's a bit hard to use, at least until bug 228794 is fixed.
I filed Bug 228825
Attachment #137580 - Attachment description: patch v2 part 2 → patch v2 part 2 (checked in)
Comment on attachment 137579 [details] [diff] [review]
patch v2 part 1

Add some comments at the spots where the reference cycles are set up and torn
down clearly saying that that's what's going on (and in particular make it very
very clear that the progress listener unhooking stuff is absolutely required to
not leak).

r=bzbarsky, assuming you've tested both download manager and progress dialog,
and tested both codepaths (select action before/after download finishes).
Attachment #137579 - Flags: review?(bz-vacation) → review+
Attached patch part 1 v3Splinter Review
made the changes bz requested.

all 4 codepaths tested successfully.
Attachment #137579 - Attachment is obsolete: true
Attachment #138077 - Flags: superreview?(darin)
Comment on attachment 138077 [details] [diff] [review]
part 1 v3

sr=darin
Attachment #138077 - Flags: superreview?(darin) → superreview+
thanks, checked in.
Status: ASSIGNED → RESOLVED
Closed: 21 years ago
Resolution: --- → FIXED
Product: Core → Core Graveyard
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: