Closed Bug 45009 Opened 25 years ago Closed 24 years ago

nsIPlugin::Initialize() and ::Shutdown aren't called

Categories

(Core Graveyard :: Plug-ins, defect, P3)

x86
All
defect

Tracking

(Not tracked)

VERIFIED FIXED
mozilla0.8.1

People

(Reporter: braden, Assigned: serhunt)

References

Details

(Keywords: memory-leak, Whiteboard: [nsbeta3-] [rtm-])

Attachments

(13 files)

Per the docs, nsIPlugin::Initialize() should be called when a plugin is first
loaded into memory, and nsIPlugin::Shutdown() should be called when it is
unloaded. Neither of these events appear to be occurring.
Doesn't happen on windows either.  changing platform to all.
OS: Linux → All
Status: NEW → ASSIGNED
Blocks: 49510
This has significant ramifications for Java plugins. Nominating for nsbeta3.
Keywords: mlk, nsbeta3
Andrei, what is the status of this bug? How serious and how involved to fix? 
Thanks.
Adding nsbeta3+ to status field.
Whiteboard: nsbeta3+
I looked thru the code and got an impression that as it currently goes xpcom 
plugins don't need to implement nsIPlugin at all. When it is first created in 
nsPluginHostImpl::SetUpPluginInstance the CreateInstance method of the 
ComponentManager takes nsIPluginInstance::GetIID(). Isn't this wrong? Shouldn't 
it be nsIPlugin::GetIID() here? We probably need to create a plugin instance 
here (not PluginInstance but rather an instance of nsPlugin) and then, on 
success, call plugin->CreateInstance.
Sean, Rusty, what do you thionk?
Correct - the way things are right now, there doesn't need to be an nsIPlugin - 
just an nsIFactory (which nsIPlugin is derived from).

In my plugin factory I implement nsIPlugin just in case it gets asked for - but 
it never gets QI'd.  Once I noticed that Initialize and Shutdown were never 
called, I just added calls to them in my factory dtor and ctor - and made sure 
that multiple calls to them would be safe in case they ever do start getting 
called by the plugin host.

Regarding CreateInstance(), I think there are a few issues outstanding 
regarding multiple mimetypes, etc. that come into play here.  What you suggest 
was probably right when the API was first created (create a plugin, then call 
CreatePluginInstance on the plugin).  I think the issue of XPCOM plugin 
registration has clouded or strayed from what was originally intended (I think 
waterson even removed nsIPlugin from the sample plugin at 
http://lxr.mozilla.org/seamonkey/source/modules/plugin/test/npsimple.cpp during 
the xpcom plugin registration creation).

per PDT: P3-P5 priority bugs changed from nsbeta3+ to nsbeta3- since we have
more important work to do for Seamonkey. If you disagree, please state your case
in the bug report and nominate for rtm. Thanks.
Whiteboard: nsbeta3+ → [nsbeta3-]
Adding rtm+.
Keywords: rtm
Whiteboard: [nsbeta3-] → [nsbeta3-] [rtm+]
PDT marking [rtm-] since it isn't clear what the impact of not fixing this would 
be. 
Whiteboard: [nsbeta3-] [rtm+] → [nsbeta3-] [rtm-]
Not a Netscape 6 RTM blocker. FUTURE. This bug has been marked Future because
the Netscape engineer it is assigned to is overburdened.
Target Milestone: --- → Future
removing target milestone (Future) in the hopes that this bug will be
re-evaluated and fixed for mozilla 1.0 or sooner.

This is particular annoying on Macintosh where 2 asserts show up (see blocking
bug #49510 I think) on every exit of the application.
Target Milestone: Future → ---
The shockwave plugin isn't receiving this NPP_Shutdown() ... this is a crash 
when using the windows debug plugin, but cannot be confirmed to be the source 
of any problem with the release build.
Nom. nsbeta1 as this blocks 49510 which may cause crashes on shutdown. However,
Andrei, since 45009 is currently only believed to be the cause of shutdown
crashes (at worst) in the release build, if you run out of time, fix other
plug-in bugs before this one. The correctness of our plug-in support while
running is more important than embarrassing (but otherwise harmless) crashes on
exit.
Keywords: nsbeta1
bug=45009
author=edburns

This fix makes it so nsIPlugin::Shutdown() is called when the app exits.

I have found that nsIPlugin::Initialize was getting correctly called
after the plugin was loaded.  I have implemented this by adding a
parameter for nsCOMPtr<nsIPlugin> to AddInstanceToActiveList and the
nsActivePlugin ctor.  

I have also modified all the find* methods in nsActivePluginList to not
find plugins that do not want to be cached.
Ed, could you please give some verbal explanation? I do not really understand 
what is the code supposed to do in nsActivePluginList::shut(). 

1. I see shutSent array allocated but I do not see it being populated with any 
data before you first use it. 

2. nsActivePluginList is essentialy a list of nsIPluginInstance instances which 
may correspond to the same nsIPlugin object so mCount might be excessive for the 
size of the shutSent array. Probably cleaner solution would be to form a list 
rather than array.

3. I am not sure this is OK to call nsIPlugin->Shutdown() before we destroy all 
the plugin nsIPluginInstance objects. We call mInstance->Destroy() in 
nsActivePlugin::~nsActivePligin which happens after your proposed 
nsIPlugin->Shutdown(). Perhaps we should create the list of nsIPlugins _pending_ 
shutdown and do it after the for cycle.
Andrei Volkov wrote:

> Ed, could you please give some verbal explanation? I do
> not really understand what is the code supposed to do in
> nsActivePluginList::shut().

This code is supposed to ensure that each existing nsPlugin
instance receives a ::Shutdown() call once.  Granted, the
first iteration code did not do that.  The second iteration
code does.

> 1. I see shutSent array allocated but I do not see it being
> populated with any data before you first use it.

Good point, fixed in second iteration patch.

> 2. nsActivePluginList is essentialy a list of
> nsIPluginInstance instances which may correspond to the
> same nsIPlugin object so mCount might be excessive for the
> size of the shutSent array. Probably cleaner solution
> would be to form a list rather than array.

True, mCount may be excessive, but it's just a local pointer
array that gets quickly destroyed.  I don't think the added
complexity would be worth the memory savings.

> 3. I am not sure this is OK to call nsIPlugin->Shutdown()
> before we destroy all the plugin nsIPluginInstance
> objects. We call mInstance->Destroy() in
> nsActivePlugin::~nsActivePligin which happens after your
> proposed nsIPlugin->Shutdown(). Perhaps we should create
> the list of nsIPlugins _pending_ shutdown and do it after
> the for cycle.

True, I have fixed this in the second iteration patch.

Please review the second iteration patch.
Couple of questions so far. 

1. what is the point in checking DoCache in find methods of nsActivePluginList? 
Currently, plugins that do not want to be cached are not present in the list 
anyway if they are not really running.

2. is it safe to call nsPluginHostImpl::Destroy from at least two places

3. if we do nsIPlugin::Shutdown in nsActivePluginList::shut (which makes sense), 
should we remove it from nsPluginHostImpl::Destroy? And

4. we probably should do this in nsActivePluginList::remove too, here writing a 
new method something like nsActivePluginList::IsLastInstance would be useful
Av wrote:
> Couple of questions so far. 

> 1. what is the point in checking DoCache in find methods
> of nsActivePluginList? Currently, plugins that do not want
> to be cached are not present in the list anyway if they
> are not really running.

Looking at the current implementation of
AddInstanceToActiveList, it seems they are indeed in the
list.  The purpose is to have them be in the list, but not
be findable.

> 2. is it safe to call nsPluginHostImpl::Destroy from at
> least two places

Probably not.  I have addressed this in the third iteration
patch.

> 3. if we do nsIPlugin::Shutdown in
> nsActivePluginList::shut (which makes sense), should we
> remove it from nsPluginHostImpl::Destroy? 

Yes, I have done this in the third iteration patch.
However, I think you need to de-allocate the mPlugins list.
This is another bug.

> 4. we probably should do this in
> nsActivePluginList::remove too, here writing a new method
> something like nsActivePluginList::IsLastInstance would be
> useful

Do what in nsActivePluginList::remove()?

>Looking at the current implementation of AddInstanceToActiveList, it seems they 
>are indeed in the list. The purpose is to have them be in the list, but not be 
>findable.

Plugins that say don't want to be cached are removed from the list in 
StopPluginInstance. They are in the list _only_ if they are currently running.

>Do what in nsActivePluginList::remove()?

nsIPlugin::Shutdown(). In fact, this seems to be the only needed place to call 
shutdown because remove is called on each element in nsActivePluginList::shut.
Attached patch nsActivePluginList::remove (deleted) — Splinter Review
Ed, please have a look at nsActivePlugin::remove method as I see it can be. 
Looks like we don't need modifications to nsActivePlugin::shut at all.
Ok that looks good. We can leave ::shut() unmodified and modify ::remove() and 
add ::IsLastInstance().  Av can you finish up on this: merge the patch, get sr= 
and check it in?  If not, I can do it.  It's up to you.  I'd just like to see 
it happen soon.

Thanks,

Ed
I'll be happy to do this. But there is still a thing you wanted in the fix which 
I don't fully understand -- plugins that don't want to be cached, see my comment 
on 2001-02-15 18:04 
> Plugins that say don't want to be cached are removed from the list in 
> StopPluginInstance. They are in the list _only_ if they are currently running.

If you can guarantee via an assertion that plugins are in the list only if they 
are running, then we can get rid of the modifications to the ::find*() methods.

Is that possible?

When we leave the page with running plugin we are always supposed to call 
nsPluginHostImpl::StopPluginInstance, we there is a check whether or not a 
plugin wants to stay in the active instance list, and if not, we do 
nsActivePluginList.remove. Isn't it sufficient garantee?
Attached patch Forth iteration (deleted) — Splinter Review
Ed, Peter, please review the forth iteration of the fix. I hope it will satisfy 
everybody. Peter, would be great if you apply and test this patch.
I'm having all sorts of stability problems with the "forth iteration" patch on 
Win32 (other platforms yet to try).

1) Tons of asserts. This one on closing a page with flash on it:
###!!! ASSERTION: This plugin is not supposed to be cached!: 'p->mStopped && 
!doCache', file S:\mozilla\modules\plugin\nglsrc\nsPluginHostImpl.cpp, line 502

2) Crashes upon exit in Shockwave.com or any game inside there.

3) Crashes when going from one page with a plugin to another or back to same one 
(Example: quicktime.com --> mozilla.org --> quicktime.com --> crash)

Haven't tried java. Where are the testcases for this bug? Am I missing something 
besides just applying the last patch?
Sorry, my fault. The assertions should use the reverse of the condition. Oh, 
man... You can just quickly change it in four ::find methods of 
nsActivePluginList, so p->mStopped && !doCache becomes !p->mStopped || doCache.

Now looking at crashes...
Peter, I cannot reproduce #3 in your previous comment.
Re-tested 5th iteration, looks good on Windows so far. Will continue to run with 
the patch and try Mac.
ALERT!!! I noticed that nsPluginHostImpl::~nsPluginHostImpl is no longer called 
on exit. Therefore, we don't have nsPluginHostImpl::Destroy called nor do we 
shut nsActivePluginList.

Anybody has an idea why?
Something is still holding on to it
Blocks: 45009
Depends on: 45009
Blocks: 58128
No longer depends on: 45009
Attached patch sixth iteration (deleted) — Splinter Review
The sixth attempt addresses crashes mentioned by peterl in his 2001-02-19 15:18 
comment. Please try.
6th patch works well on Windows. I could not reproduce any sort of crash. I will 
try on the Mac. This patch does NOT fix bug 58128 :( 

It would still be nice to run some regression tests as this change could effect 
a lot of plugins.
AV, for some reason, I can't get this patch to apply.  Can you please help me?

D:\Projects\trunk\mozilla\modules\plugin\nglsrc>patch -u -i 
nsPluginHostImpl.h.patch nsPluginHostImpl.h
patch -u -i nsPluginHostImpl.h.patch nsPluginHostImpl.h
patching file `nsPluginHostImpl.h'
Hunk #1 FAILED at 27.
Hunk #2 FAILED at 81.
Hunk #3 FAILED at 119.
Hunk #4 FAILED at 298.
Hunk #5 FAILED at 342.
5 out of 5 hunks FAILED -- saving rejects to nsPluginHostImpl.h.rej

Patch (#25660) is good on Mac. All checks out and Shutdown is properly being 
called when the browser shuts down.

It is still unclear if the Shutdown() should be called when "the last instance 
of a plugin is Destroyed." However, if the cache is set to 0 then, then shutdown 
should always be called?
Oh and r=peterl if the Java folks approve
peterl wrote:
> It is still unclear if the Shutdown() should be called when "the last instance 
> of a plugin is Destroyed."

The spec says:
'Communicator calls this function once after the last instance of your plug-in 
is destroyed, before unloading the plug-in library itself. Use NPP_Shutdown to 
delete any data allocated in NPP_Initialize to be shared by all instances of a 
plug-in.'

> However, if the cache is set to 0 then, then shutdown should always be called?

Again, only on the destruction of last instance. If we, say, have two embeds on 
the page and leave it, we deatroy instances one after another, and Shutdown on 
the nsIPlugin object is supposed to be called after the last instance is 
destroyed.
BTW, Peter, do you see nsPluginHostImpl::Observe reliably called?
Observe is being called. I like this patch. 

But, according to the spec, I don't think Shutdown is being called when the last 
instanstance is destroyed. I set a breakpoint in Shutdown() and visited a page 
with Flash. When I left the page, ns4xPlugin::Shutdown() was never called. I 
tried the same with two of the same plugin on the page, and it was not called. 
When I left the page, all instances should have been Destroyed and therefore 
Shutdown should have been called, if I am understanding the spec correctly?
I'm planning on trying this out today.
peter: when we leave the page we don't destroy the instance but rather cache it 
setting Stop flag. This is the whole point of having nsActivePluginList which is 
the list of plugin instance objects, some of them may be not running.
I have applied these files to my trunk build.  This looks good to me.  
r=edburns.
Av what's the status?
Waiting for sr from waterson.
You never set mDestroyed to PR_TRUE; I think you probably want to do that
immediately after checking in in nsPluginHostImpl::Destroy()? (Do you want to
botch-assert if somebody tries to destroy the nsPluginHostImpl twice? Or use the
nsPluginHostImpl after it's been destroyed?)

At a minimum, be sure to set mIsDestroyed, and sr=waterson
Target Milestone: --- → mozilla0.8.1
Checked in. Marking fixed.
Status: ASSIGNED → RESOLVED
Closed: 24 years ago
Resolution: --- → FIXED
OUCH!!!!

XPCOM plugins now get wrapped with the 4x legacy classes because the call to 
GetPluginFactory moved up before the nsComponentManager::CreateInstance() 
call.  As implemented, GetPluginFactory() should only be called if the 
componentManager failed to create an xpcom plugin.

Looks like GetPluginFactory call was moved in order to get a nsIPlugin* to pass 
into the call to AddInstanceToActiveList().

Either need to move GetPluginFactory() back, or modify it so that it is xpcom 
savvy.  Looks like the call to 
   PR_FindSymbol(pluginTag->mLibrary, "NSGetFactory");
is not satisfactory for determining if a plugin module is an xpcom plugin or a 
4x plugin.
bug 72017 has been opened to address the problems (in last comment) introduced 
by the patch for this bug.
verif (stamp)
Status: RESOLVED → VERIFIED
Product: Core → Core Graveyard
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: