Closed
Bug 745540
Opened 12 years ago
Closed 12 years ago
ConcurrentModificationException thrown when unregistering a gecko event listener while the listener is running
Categories
(Firefox for Android Graveyard :: General, defect)
Tracking
(firefox14 fixed, blocking-fennec1.0 beta+)
RESOLVED
FIXED
Firefox 14
People
(Reporter: kats, Assigned: kats)
References
Details
Attachments
(1 file, 1 obsolete file)
6.07 KB,
patch
|
blassey
:
review+
rnewman
:
feedback+
|
Details | Diff | Splinter Review |
I added a Preferences:Data listener that unregisters itself when it gets triggered, and to my amazement it threw a ConcurrentModificationException! Turns out this is not very amazing once you look at the code, because there is no multithreaded access consideration given to the mEventListeners structure that these are stored in. Since we normally only unregister listeners in onDestroy() methods, this hasn't cropped up yet, but really all the code that deals with mEventListeners only works by accident.
Attachment #615146 -
Flags: review?(blassey.bugs)
Assignee | ||
Updated•12 years ago
|
Assignee: nobody → bugmail.mozilla
Comment 1•12 years ago
|
||
Comment on attachment 615146 [details] [diff] [review] Make mEventListeners access thread-safe Review of attachment 615146 [details] [diff] [review]: ----------------------------------------------------------------- ::: mobile/android/base/GeckoAppShell.java @@ +1684,5 @@ > + } else { > + // we should not modify "listeners" directly here, because this > + // method could be called from a GeckoEventListener implementation > + // that is executing right now. Modifying the "listeners" object > + // that may be being iterated through in handleGeckoMessage would it easier to synchronize on listeners here and in handleGeckoMessage?
Assignee | ||
Comment 2•12 years ago
|
||
(In reply to Brad Lassey [:blassey] from comment #1) > Comment on attachment 615146 [details] [diff] [review] > would it easier to synchronize on listeners here and in handleGeckoMessage? No, because they might be on the same thread, and so the synchronization will not block anything. i.e.: 1. handleGeckoMessage does synchronize(listeners) 2. handleGeckoMessage calls handleMessage(event) 3. handleMessage calls unregisterGeckoEventListener(this) 4. unregisterGeckoEventListener does synchronize(listeners) // this works fine, it's the same thread 5. listeners array is mutated ... n. handleGeckoMessage blows up
Assignee | ||
Comment 3•12 years ago
|
||
:rnewman suggested using CopyOnWriteArrayList instead to avoid reinventing it, so updated the patch to do that.
Attachment #615146 -
Attachment is obsolete: true
Attachment #615146 -
Flags: review?(blassey.bugs)
Attachment #615383 -
Flags: review?(blassey.bugs)
Attachment #615383 -
Flags: feedback?(rnewman)
Comment 4•12 years ago
|
||
Comment on attachment 615383 [details] [diff] [review] Make mEventListeners access thread-safe (v2) Review of attachment 615383 [details] [diff] [review]: ----------------------------------------------------------------- ::: mobile/android/base/GeckoAppShell.java @@ +115,5 @@ > private static Boolean sNSSLibsLoaded = false; > private static Boolean sLibsSetup = false; > private static File sGREDir = null; > > + private static Map<String, CopyOnWriteArrayList<GeckoEventListener>> mEventListeners This can probably be a less specific type... @@ +1719,5 @@ > + } > + listeners.remove(listener); > + if (listeners.size() == 0) { > + mEventListeners.remove(event); > + } I'd consider whether this cleanup is worthwhile, compared to just leaving the empty list around and sometimes doing less work in the register case... considering the case of frequently registering and unregistering listeners for the same event. @@ +1767,5 @@ > } catch (Exception ex) { } > return ret.toString(); > } > > + CopyOnWriteArrayList<GeckoEventListener> listeners; This can be less specific; will make your life easier if you ever switch internal representations.
Attachment #615383 -
Flags: feedback?(rnewman) → feedback+
Assignee | ||
Comment 5•12 years ago
|
||
(In reply to Richard Newman [:rnewman] from comment #4) > > I'd consider whether this cleanup is worthwhile, compared to just leaving > the empty list around and sometimes doing less work in the register case... > considering the case of frequently registering and unregistering listeners > for the same event. > Yeah, I wasn't really sure which case I should optimize for there. In practice we don't unregister things until shutdown anyway so it doesn't really matter. > > This can be less specific; will make your life easier if you ever switch > internal representations. The initial version of the patch used just List<GeckoEventListener> but with the change we are pretty much forced to use a CopyOnWriteArrayList; changing to a regular ArrayList or LinkedList will un-fix the original bug. Since we *are* constrained to a specific internal representation I figured it would be better to make that explicit in the type.
Updated•12 years ago
|
blocking-fennec1.0: ? → beta+
Updated•12 years ago
|
Attachment #615383 -
Flags: review?(blassey.bugs) → review+
Assignee | ||
Comment 6•12 years ago
|
||
https://hg.mozilla.org/integration/mozilla-inbound/rev/55f527f49d54
status-firefox14:
--- → fixed
Target Milestone: --- → Firefox 14
Comment 7•12 years ago
|
||
https://hg.mozilla.org/mozilla-central/rev/55f527f49d54
Status: NEW → RESOLVED
Closed: 12 years ago
Resolution: --- → FIXED
Updated•3 years ago
|
Product: Firefox for Android → Firefox for Android Graveyard
You need to log in
before you can comment on or make changes to this bug.
Description
•