-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
8305072: Win32ShellFolder2.compareTo is inconsistent #18126
8305072: Win32ShellFolder2.compareTo is inconsistent #18126
Conversation
👋 Welcome back aivanov! A progress list of the required criteria for merging this PR into |
@aivanov-jdk The following label will be automatically applied to this pull request:
When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command. |
Webrevs
|
The desktop folder on Windows 10 does not include the Personal (Documents) folder.
@@ -522,7 +522,7 @@ static int compareShellFolders(Win32ShellFolder2 sf1, Win32ShellFolder2 sf2) { | |||
boolean special1 = sf1.isSpecial(); | |||
boolean special2 = sf2.isSpecial(); | |||
|
|||
if (special1 || special2) { | |||
if (special1 && special2) { |
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.
Could you please say something on how/why this change solves it ?
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.
It is well described in a JBS comment by the submitter.
Let's consider the failing case where:
a = C:\Users\<user>\Documents(true)
b = C:\Users\<user>(false)
c = C:\Users\<user>\Documents(false)
The value in parentheses is isSpecial()
flag.
When a
and c
are compared, special1 = true
and special2 = false
, therefore the code flow enters this if
-block. Because the equals
method doesn't take into account the isSpecial
flag, both i1
and i2
are 0.
jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java
Lines 534 to 535 in 7bccc84
int i1 = topFolderList.indexOf(sf1); | |
int i2 = topFolderList.indexOf(sf2); |
Thus, a
and c
are considered equal, which breaks the general contract of Comparable.compareTo
.
If you look below this if
-statement:
jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java
Lines 545 to 550 in 7bccc84
// Non-file shellfolders sort before files | |
if (special1 && !special2) { | |
return -1; | |
} else if (special2 && !special1) { | |
return 1; | |
} |
The comment and the code say that any special folder sorts above any regular folder. Therefore the code shouldn't enter that if
-block above if only one of the folders is special — the order is already well-defined for such case.
The purpose of the if
-block is to make some of the special folders even more special. In other words, it ensures the following special folders—getPersonal
, getDesktop
, getDrives
, getNetwork
—are at the top of the list, above any other special folders.
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.
So, changing the condition in the if
-block from special1 || special2
to special1 && special2
makes the sorting order consistent because the relation is now transitive:
a < b & b < c therefore a < c
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.
Hi, I'm the submitter of the original bug report. I can confirm that you got the reason for the change exactly right.
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.
@uckelman, Your message is hidden until you accept OpenJDK Terms of Use.
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, @uckelman, for the detailed analysis. Greatly appreciated.
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.
@uckelman Is there a way to reproduce the original bug in the user's environment?
I think there's a bug in JDK which leads to two Documents folders in the list. If the bug is still reproducible, collecting more data will help us identify the problem and fix it.
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.
If I can get in contact with the user, I expect he'd still be able to trigger the bug with my test case, yeah. I'll try to get his attention.
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 haven't heard back yet. I hope investigating the second bug will not hold up the fix for the first bug getting merged.
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 haven't heard back yet. I hope investigating the second bug will not hold up the fix for the first bug getting merged.
It's not a show-stopper. These are different bugs. If possible, I'd like to follow up and find the root cause of why there are two identical folders in the file list.
@aivanov-jdk 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 532 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 |
Any other reviewer? |
/integrate |
Going to push as commit 2fcb816.
Your commit was automatically rebased without conflicts. |
@aivanov-jdk Pushed as commit 2fcb816. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
Will this be backported to Java 21 and 22? It would be very helpful if it could be. |
It is already backported to 22. |
The implementation of
Win32ShellFolder2.compareTo
is inconsistent: there are cases wherea < b & b < c but a == c
which violates its general contract.
In particular, it happens for the personal folder (Documents) if it is listed twice: as a special and as a regular folder.
The evaluation performed by the submitter of the bug provided enough details to create a test, reproduce the problem and finally resolve it.
Without the fix, the regression test always fails:
as well as for the reverse case:
a > b & b > c
.How it is possible to have the same folder in a list of files twice remains unknown. I believe it is another bug in JDK, however, no one has been able to reproduce it so far.
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/18126/head:pull/18126
$ git checkout pull/18126
Update a local copy of the PR:
$ git checkout pull/18126
$ git pull https://git.openjdk.org/jdk.git pull/18126/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 18126
View PR using the GUI difftool:
$ git pr show -t 18126
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/18126.diff
Webrev
Link to Webrev Comment