-
Notifications
You must be signed in to change notification settings - Fork 543
8347753: VetoableListDecorator doesn't accept its own sublists for bulk operations #1679
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
👋 Welcome back mstrauss! A progress list of the required criteria for merging this PR into |
|
@mstr2 This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be: You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 26 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
Webrevs
|
|
|
||
| private class VetoableSubListDecorator implements List<E> { | ||
| /** | ||
| * Returns the specified collection as an unmodifiable list that can safely be used in all bulk |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think it might be easier to create a defensive copy always?
In other words, can we guarantee that it is impossible for the user to create a convoluted code involving maybe two VetoableListDecorators where the second one loops back the changes to the first one, however ridiculous that might sound?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way I see it, the situation that erroneously triggers ConcurrentModificationException only happens when VetoableListDecorator accesses its own sublist:
try {
modCount++;
boolean ret = list.addAll(index, c); // --> c is its own sublist
...Since modCount is modified first, and the sublist refers back to the same modified modCount, the exception occurs. It can't occur when we are dealing with another list (or a sublist of another list), since in this case there is no self-referential conflict.
The way ArrayList circumvents this problem is by incrementing modCount only after the operation is done, not before it has started; it doesn't create a defensive copy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for clarification! I'll try to come up with a test (and I think even if I succeed, it does not mean that your solution is not good, since the caller can always create a defensive copy themselves).
BTW, what were you doing to trigger this bug?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, what were you doing to trigger this bug?
This happened when I was writing some tests for the other VetoableListDecorator PRs...
andy-goryachev-oracle
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The scenario I was referring to is impossible, I think.
One possible alternative is to create the defensive copy each time, this will save one extra pointer every time an iterator or a sublist gets created (these objects might be long lived). The code in this PR creates a copy in many (most?) cases anyway, and in my opinion, the memory is more precious resource that CPU cycles (i.e. using extra memory costs many more CPU cycles in garbage collection etc.), so please consider that.
- some minor suggestions
| public void testAddAll_subList() { | ||
| list.addAll(list.subList(0, 2)); | ||
| assertSingleCall(new String[] {"foo", "bar"}, new int[] {4, 4}); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: also check that the list contains the newly added elements?
(here and in added tests that involve subList?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added checks for the list content in all modified tests.
I don't quite understand what you mean. Can you elaborate? |
What I mean is simply get rid of the extra pointer like |
Okay, I see. We can't do that, because a sublist is specified to be a live view onto the source list. After all, |
good point, thanks for pointing this out. |
andy-goryachev-oracle
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
|
@mstr2 This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration! |
kevinrushforth
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code changes look good. I confirm that the new tests fail without the fix and pass with the fix.
|
/integrate |
|
Going to push as commit 4f0f992.
Your commit was automatically rebased without conflicts. |
Passing a
VetoableListDecorator.subList()to any of its bulk operations (addAll,setAll,removeAll,retainAll) throwsConcurrentModificationException. The reason is that theVetoableListDecorator.modCountfield is incremented before the underlying list's bulk operation is invoked, which causes a mismatch when the sublist is interrogated by the bulk operation.However, simply updating the
modCountfield after the underlying list was modified also doesn't work, as in this case listeners can't see the correct value formodCountin their callback. The fix is to make a defensive copy of the sublist before invoking the underlying list's bulk operation./reviewers 2
Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/1679/head:pull/1679$ git checkout pull/1679Update a local copy of the PR:
$ git checkout pull/1679$ git pull https://git.openjdk.org/jfx.git pull/1679/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 1679View PR using the GUI difftool:
$ git pr show -t 1679Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/1679.diff
Using Webrev
Link to Webrev Comment