Closed Bug 174320 Opened 23 years ago Closed 20 years ago

When an event handler removes itself the next handler is skipped

Categories

(Core :: DOM: UI Events & Focus Handling, defect)

defect
Not set
critical

Tracking

()

VERIFIED FIXED

People

(Reporter: neil, Assigned: neil)

References

()

Details

Attachments

(6 files, 1 obsolete file)

Using Build ID: 2002100920 Many Mozilla components and extensions need to initialize their dynamic overlays which is typically done using addEventListener("load", myInitFunc, false); but if myInitFunc contains a call to removeEventListener("load", myInitFunc, false); the following event handler gets skipped.
Attached file Test case
This test case uses the "command" event which is easier to demonstrate. Steps to reproduce problem: 1. Click the "Add" button three times. (OK each alert) 2. Click the "Test" button. OK each alert. 3. Click the "Test" button. Expected results: 3 alerts at step 2 Actual results: alerts 1 & 3 at step 2; alert 2 at step 3.
taking
Assignee: joki → bryner
QA Contact: rakeshmishra → trix
Note (might be obvious from Neil's comment though): this bug will not occur if you pass true for addEventListener's capture parameter.
Not true, the test case fails for capturing events too. Note that in the real world capturing event handlers get hit more frequently so the effect is less noticable.
Hixie, do you know what correct behaviour is?
Hixie, this bug is about listeners that *aren't* removed...
Why would the listeners that aren't removed be in any way affected?
Obvious answer, Hixie: because it's a *bug* in Mozilla.
Jens: I was replying to comment 6, and was asking why the _spec_ would say anything about other listeners.
this really *should* be fixed as extensions become more & more popular and it affects Mozilla Suite as well as FireFox
Flags: blocking1.7+
(In reply to comment #5) By implication, then, removing the event on the opposite phase should not manifest the bug (which seems to hold true -- change the third removeEventListener param in your test-case to false). Add on capture, remove on bubble (or vice versa) -- then everything seems to work as expected. I guess this could be seen as a work-around (for most cases) until the bug is squished.
Oops, that should have said: "...change the third removeEventListener param in your test-case to true..."
Flags: blocking1.7+
Flags: blocking1.7+
Flags: blocking1.7+ → blocking1.7?
Flags: blocking1.7? → blocking1.7-
Flags: blocking-aviary1.0?
Apparently these are side effects that I have been running into constantly on the Avairy build of FireFox (nightlies)... I hope no one minds me posting this here since I'm very unfamiliar with Bugzilla and appropriateness. Reference post in EMButtons Extension Thread (also relates to multiple extensions.) http://forums.mozillazine.org/viewtopic.php?p=724617#724617 Put here for your ease to read... My post: Note: Sort is not being used so it is not an event handler bug. Four Conflicts that I've come across with EMButtons and Three Different Extensions and FireFox. First conflict is made reference to here which involves WeatherFox (any version (tested this)) and as far as I know any version of EMButtons (tested with 0.9.0 and 0.10.1). (The example is with a developer version of WeatherFox 0.2.5 (found in the weatherfox.mozdev.org/source.html (through the cvs) (but it conflicts with 0.2.1 as well) and EMButtons 0.10.1) Second conflict deals with Window-Q 0.1 d11 (metaphor) pass10 what happens in short is: When you install EMButtons First and the Install Window-Q 0.1 d11 (metaphor) pass10 found in the Window-Q thread it causes EMButtons to not use the concise or performace options. Even if they weren't set before hand. If they were set before hand they lose them immediately and turning them on or off will not change anything. So you have to install Window-Q First and then EMButtons. Third conflict --- I have only been able to get the short-cut overlays and functions to work in one way... EVER. I have to install Ad-Block first then installing EMButtons anytime after that and it will work. No matter what. If Ad-Block is not installed first EMButtons will never retrieve its overlay functions. Neutral And Fourth conflict, only when EMButtons is set as a Sidebar or Tab will this second buggy Extension Manager Window pop up. I am trying hard not to make a fuss about these these bugs but they are quite annoying when you Keep running into them. Moonwolf's reply: here is no event handler involved in the sorting, not sure why you thought that. First: As crafteh said in the WeatherFox thread, this is his fault. There's nothing I can do about it. Second: Event handler bug. Window-Q is removing an event handler and stopping the one which applies the enhanced modes in EMbuttons from being loaded. Firefox loads extensions in reverse order. Third: Event handler bug. An event handler applies the shortcut keys to the Tools menu. Have you voted for the bug and posted your problems to it? If it's irritating you this much you really should. Fourth: As I said before, the code which loads the EM after a drag and drop is well hidden. I don't have an unlimited amount of time to work on EMbuttons, and it's entirely possible that this event is coded in a way that won't allow me to alter it. Fixing this bug is low priority because it isn't doing any real harm. Summary/Conclusion: I find the conflicts listed in my post to extremly annoying and have to selectively install my extensions in the correct way otherwise I will have improper installations. I believe many people could run into this and I hope that this really would be considered fully.
Flags: blocking-aviary1.0? → blocking-aviary1.0-
Whoops, I seem to have fixed this. Patch in a sec.
Rather than simply looping through the live list of listeners (which causes us to break in a bunch of interesting ways), this patch clones the list and walks that instead. Now, if the DOM Spec didn't want us to care about deleted listeners, that would be it - but it does, so the code checks it's "in sync" with the live list, and if it isn't, resyncs itself. All the resync is doing is finding the next (starting with the current) listener that is still in the live list. This means additions are ignored and deletions are followed, as per spec. With this patch both the test cases on this bug pass, as do two test cases I wrote to check the spec (one for addition, one for deletion). Since event listeners added during processing are NOT executed after this change, it may cause some regressions.
Comment on attachment 161541 [details] [diff] [review] Use a clone of the list + some magic instead of the live list >+ // Clone the listener array. >+ nsVoidArray *safeListeners = new nsVoidArray(listeners->Count()); You never free this. Possibly you should create an auto variable instead of a pointer i.e. nsVoidArray safelisteners(listeners->Count()); >+ while (k < safeListeners->Count()) { >+ for (int l = 0; listeners && l < listeners->Count(); l++) { >+ if (listeners->ElementAt(l) == safeListeners->ElementAt(k)) { >+ synced = PR_TRUE; >+ break; >+ } >+ } You might want to use listeners->IndexOf to see if the listener still exists. In fact, if (listeners->IndexOf(ls) == -1) continue; might even work. But I'm worried that deleting a listener might leave a dangling pointer in your clone. >+ nsListenerStruct* ls = NS_STATIC_CAST(nsListenerStruct*, safeListeners->ElementAt(k));
(In reply to comment #18) > (From update of attachment 161541 [details] [diff] [review]) > >+ // Clone the listener array. > >+ nsVoidArray *safeListeners = new nsVoidArray(listeners->Count()); > You never free this. Possibly you should create an auto variable instead of a > pointer i.e. nsVoidArray safelisteners(listeners->Count()); Point, it occured to me when I went to bed that I probably wasn't freeing it (though it was emptying the array before leaking the object ;) ). > >+ while (k < safeListeners->Count()) { > >+ for (int l = 0; listeners && l < listeners->Count(); l++) { > >+ if (listeners->ElementAt(l) == safeListeners->ElementAt(k)) { > >+ synced = PR_TRUE; > >+ break; > >+ } > >+ } > You might want to use listeners->IndexOf to see if the listener still exists. > In fact, if (listeners->IndexOf(ls) == -1) continue; might even work. But I'm > worried that deleting a listener might leave a dangling pointer in your clone. Well, it will do - that's how it can tell if it still needs to call it. I can attempt a much more complicated version that keeps track of exactly where it is in the list using a private field that's updated as the list changes, if that would be better.
Attached patch Updated patchSplinter Review
Not sure the |safeListeners = nsnull;| line is nessessary, or how I missed |IndexOf| in nsVoidArray.h before, but this is the patch with changes and still works. :)
Attachment #161541 - Attachment is obsolete: true
Attached patch Reduced patchSplinter Review
I believe this should have the same effect as attachment 161595 [details] [diff] [review].
Comment on attachment 161618 [details] [diff] [review] Reduced patch + nsVoidArray originalListeners(count); + originalListeners = *listeners; That should be an nsAutoVoidArray to avoid mostly unnecessary malloc overhead.
Assignee: bryner → neil.parkwaycc.co.uk
Is there plans to put the patch (which needs to be updated per the previous comment) into the core any time soon? This really should be fixed ASAP as it can cause extensions to conflict with each other.
Also if the bug is truely in /content/events/src/nsEventListenerManager.cpp then I think the Component should be listed as "DOM: Events". As it is currently set, the bug does not show up in the list Event Bugs.
Ignore my last comment, it accidently got sent when I did not mean for it to.
Asking for blocking-aviary1.1. This bug almost has a patch and it is one of main causes of extensions conflicts as far as I can tell from reading the MZ forums.
Flags: blocking-aviary1.1?
(In reply to comment #28) > Asking for blocking-aviary1.1. This bug almost has a patch and it is one of main > causes of extensions conflicts as far as I can tell from reading the MZ forums. If it blocks 1.1 then I think it should also block 1.8b since the problem exists in the 1.8 baseline (which will become Mozilla 1.8, Firefox 1.1 and Thunderbird 1.1) and like you said it is nearly has a patch. See http://www.mozillazine.org/talkback.html?article=6004
Flags: blocking1.8b?
Johnny, what do you think about this one? Can you help get it in for 1.8b?
too late for 1.8b, transferring request to b2, and requesting review from jst
Flags: blocking1.8b?
Flags: blocking1.8b2?
Flags: blocking1.8b-
Comment on attachment 161618 [details] [diff] [review] Reduced patch + nsVoidArray originalListeners(count); Make that nsAutoVoidArray. r+sr=jst
Attachment #161618 - Flags: superreview+
Attachment #161618 - Flags: review?(jst)
Attachment #161618 - Flags: review+
I couldn't, they're not assignment compatible.
Status: NEW → RESOLVED
Closed: 20 years ago
Resolution: --- → FIXED
Thanks James and Neil very much! Verified using Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050218 Firefox/1.0+ - all four testcases pass. (I would like to reiterate that this patch also fixed another problem not mentioned in Summary or in the original report - listeners added with addEventListener while a listener is running will not be called until the event finishes processing - see attachment 161616 [details] (fourth testcase) and http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget-addEventListener)
Status: RESOLVED → VERIFIED
Flags: blocking-aviary1.1?
Flags: blocking1.8b2?
*** Bug 290336 has been marked as a duplicate of this bug. ***
I'm getting this too on Firefox 1.0.3. Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.7) Gecko/20050414 Firefox/1.0.3
(In reply to comment #36) > I'm getting this too on Firefox 1.0.3. That's normal - the bug was fixed on the development trunk, meaning it only will be in Firefox 1.1. New Firefox 1.0.x releases do not pick up all fixes automatically.
Component: Event Handling → User events and focus handling
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: