-
Bug
-
Resolution: Duplicate
-
P3
-
7u80, 8u40, 9
-
x86_64
-
windows_7
FULL PRODUCT VERSION :
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) Client VM (build 25.45-b02, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
When pasting an item into a Java application, SunClipboard eventually calls the method "DataTransferer.setToSortedDataFlavorArray()". This ultimately calls Array.sort on a DataFlavor set using a DataFlavor.DataFlavorComparator.
DataFlavor.DataFlavorComparator is passed to java.util.TimSort, which, depending on the data being sorted, sometimes throws the exception "java.lang.IllegalArgumentException: Comparison method violates its general contract!". TimSort does a check when sorting to verify if the comparator given to it is valid. With some DataFlavor sets, this check will fail.
It appears DataFlavor.DataFlavorComparator does not correctly honor the requirements that Comparator mandates for the .compare method.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Copy and paste data into a Java application. The bug is dependent on the order of the DataFlavor(s) (which is in a HashSet) and the type of DataFlavor(s), and there must be at least 32 DataFlavor(s) in order for TimSort to be used, so it's extremely difficult to reproduce in a normal application.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(Unknown Source)
at java.util.TimSort.mergeAt(Unknown Source)
at java.util.TimSort.mergeForceCollapse(Unknown Source)
at java.util.TimSort.sort(Unknown Source)
at java.util.Arrays.sort(Unknown Source)
at sun.awt.datatransfer.DataTransferer.setToSortedDataFlavorArray(Unknown Source)
at sun.awt.datatransfer.ClipboardTransferable.<init>(Unknown Source)
at sun.awt.datatransfer.SunClipboard.getContents(Unknown Source)
at javax.swing.TransferHandler$TransferAction.actionPerformedImpl(Unknown Source)
at javax.swing.TransferHandler$TransferAction.access$800(Unknown Source)
at javax.swing.TransferHandler$TransferAction$1.run(Unknown Source)
at javax.swing.TransferHandler$TransferAction$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at javax.swing.TransferHandler$TransferAction$2.run(Unknown Source)
at javax.swing.TransferHandler$TransferAction$2.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at javax.swing.TransferHandler$TransferAction.actionPerformed(Unknown Source)
at javax.swing.text.JTextComponent.invokeAction(Unknown Source)
at javax.swing.text.JTextComponent.paste(Unknown Source)
at javax.swing.text.DefaultEditorKit$PasteAction.actionPerformed(Unknown Source)
at javax.swing.SwingUtilities.notifyAction(Unknown Source)
at javax.swing.JComponent.processKeyBinding(Unknown Source)
at javax.swing.JComponent.processKeyBindings(Unknown Source)
at javax.swing.JComponent.processKeyEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.KeyboardFocusManager.redispatchEvent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(Unknown Source)
at jSSS.jgui.KeyEventManager.dispatchKeyEvent(KeyEventManager.java:132)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
at jSSS.jgui.KeyEventManager.dispatchEvent(KeyEventManager.java:455)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at jSSS.jgui.sssworker.SSSMouseBlocker.dispatchEvent(SSSMouseBlocker.java:105)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
REPRODUCIBILITY :
This bug can be reproduced rarely.
---------- BEGIN SOURCE ----------
import sun.awt.datatransfer.DataTransferer;
import java.awt.datatransfer.DataFlavor;
import java.util.LinkedHashSet;
import java.util.Set;
public class Test {
public static void main(String args[]) throws ClassNotFoundException {
// If the set is smaller than TimSort.MIN_MERGE (32), TimSort will use a binary sort instead which won't
// enter the code branch that we want.
String[] mimes = new String[]{
"text/plain; class=java.lang.Object; charset=unicode",
"text/plain; class=java.io.InputStream; charset=unicode",
"text/html; document=fragment; class=java.nio.ByteBuffer; charset=windows-1252",
"text/html; document=all; class=java.nio.ByteBuffer; charset=ISO-8859-1",
"text/html; document=all; class=\"[B\"; charset=UTF-16",
"application/x-java-serialized-object; class=java.lang.String",
"application/unknown; class=java.lang.Object",
"text/html; document=selection; class=java.io.InputStream; charset=UTF-16BE",
"text/html; document=selection; class=\"[B\"; charset=UTF-16BE",
"text/plain; class=java.io.InputStream; charset=UTF-8",
"text/html; document=fragment; class=java.io.InputStream; charset=US-ASCII",
"text/plain; class=java.nio.ByteBuffer; charset=UTF-16LE",
"text/plain; class=\"[B\"; charset=ISO-8859-1",
"text/html; document=all; class=java.io.InputStream; charset=UTF-16BE",
"text/html; document=all; class=java.nio.ByteBuffer; charset=UTF-16BE",
"text/unknown; class=java.lang.String",
"text/plain; class=java.lang.Object",
"text/html; document=all; class=java.nio.ByteBuffer; charset=US-ASCII",
"text/html; document=fragment; class=java.io.InputStream; charset=windows-1252",
"text/html; class=java.lang.Object; charset=unicode",
"text/html; document=all; class=java.nio.ByteBuffer; charset=UTF-8",
"unknown/flavor; class=java.lang.Object",
"text/html; document=fragment; class=java.io.InputStream; charset=UTF-8",
"text/html; document=fragment; class=java.io.InputStream; charset=ISO-8859-1",
"text/plain; class=java.io.Reader",
"text/html; document=selection; class=java.io.InputStream; charset=UTF-16LE",
"text/html; document=selection; class=java.nio.ByteBuffer; charset=windows-1252",
"text/html; document=all; class=\"[B\"; charset=US-ASCII",
"text/html; document=all; class=\"[B\"; charset=UTF-16LE",
"text/html; document=fragment; class=java.lang.String; charset=Unicode",
"text/plain; class=\"[C\"; charset=Unicode",
"text/html; document=fragment; class=java.io.InputStream; charset=UTF-16LE"
};
// We have to use a LinkedHashSet as this bug is dependent on the order of the entries in the set.
// Normally SunClipboard uses a HashSet which makes it difficult to replicate the test reliably.
final Set<DataFlavor> flavorSet = new LinkedHashSet<>(32);
for (String mime : mimes) {
flavorSet.add(new DataFlavor(mime));
}
// This will throw an IllegalArgumentException.
DataTransferer.setToSortedDataFlavorArray(flavorSet);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
-Djava.util.Arrays.useLegacyMergeSort=true as a JVM parameter will use the legacy sort and avoids the TimSort which performs this validation.
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) Client VM (build 25.45-b02, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
When pasting an item into a Java application, SunClipboard eventually calls the method "DataTransferer.setToSortedDataFlavorArray()". This ultimately calls Array.sort on a DataFlavor set using a DataFlavor.DataFlavorComparator.
DataFlavor.DataFlavorComparator is passed to java.util.TimSort, which, depending on the data being sorted, sometimes throws the exception "java.lang.IllegalArgumentException: Comparison method violates its general contract!". TimSort does a check when sorting to verify if the comparator given to it is valid. With some DataFlavor sets, this check will fail.
It appears DataFlavor.DataFlavorComparator does not correctly honor the requirements that Comparator mandates for the .compare method.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Copy and paste data into a Java application. The bug is dependent on the order of the DataFlavor(s) (which is in a HashSet) and the type of DataFlavor(s), and there must be at least 32 DataFlavor(s) in order for TimSort to be used, so it's extremely difficult to reproduce in a normal application.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(Unknown Source)
at java.util.TimSort.mergeAt(Unknown Source)
at java.util.TimSort.mergeForceCollapse(Unknown Source)
at java.util.TimSort.sort(Unknown Source)
at java.util.Arrays.sort(Unknown Source)
at sun.awt.datatransfer.DataTransferer.setToSortedDataFlavorArray(Unknown Source)
at sun.awt.datatransfer.ClipboardTransferable.<init>(Unknown Source)
at sun.awt.datatransfer.SunClipboard.getContents(Unknown Source)
at javax.swing.TransferHandler$TransferAction.actionPerformedImpl(Unknown Source)
at javax.swing.TransferHandler$TransferAction.access$800(Unknown Source)
at javax.swing.TransferHandler$TransferAction$1.run(Unknown Source)
at javax.swing.TransferHandler$TransferAction$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at javax.swing.TransferHandler$TransferAction$2.run(Unknown Source)
at javax.swing.TransferHandler$TransferAction$2.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at javax.swing.TransferHandler$TransferAction.actionPerformed(Unknown Source)
at javax.swing.text.JTextComponent.invokeAction(Unknown Source)
at javax.swing.text.JTextComponent.paste(Unknown Source)
at javax.swing.text.DefaultEditorKit$PasteAction.actionPerformed(Unknown Source)
at javax.swing.SwingUtilities.notifyAction(Unknown Source)
at javax.swing.JComponent.processKeyBinding(Unknown Source)
at javax.swing.JComponent.processKeyBindings(Unknown Source)
at javax.swing.JComponent.processKeyEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.KeyboardFocusManager.redispatchEvent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(Unknown Source)
at jSSS.jgui.KeyEventManager.dispatchKeyEvent(KeyEventManager.java:132)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
at jSSS.jgui.KeyEventManager.dispatchEvent(KeyEventManager.java:455)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at jSSS.jgui.sssworker.SSSMouseBlocker.dispatchEvent(SSSMouseBlocker.java:105)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
REPRODUCIBILITY :
This bug can be reproduced rarely.
---------- BEGIN SOURCE ----------
import sun.awt.datatransfer.DataTransferer;
import java.awt.datatransfer.DataFlavor;
import java.util.LinkedHashSet;
import java.util.Set;
public class Test {
public static void main(String args[]) throws ClassNotFoundException {
// If the set is smaller than TimSort.MIN_MERGE (32), TimSort will use a binary sort instead which won't
// enter the code branch that we want.
String[] mimes = new String[]{
"text/plain; class=java.lang.Object; charset=unicode",
"text/plain; class=java.io.InputStream; charset=unicode",
"text/html; document=fragment; class=java.nio.ByteBuffer; charset=windows-1252",
"text/html; document=all; class=java.nio.ByteBuffer; charset=ISO-8859-1",
"text/html; document=all; class=\"[B\"; charset=UTF-16",
"application/x-java-serialized-object; class=java.lang.String",
"application/unknown; class=java.lang.Object",
"text/html; document=selection; class=java.io.InputStream; charset=UTF-16BE",
"text/html; document=selection; class=\"[B\"; charset=UTF-16BE",
"text/plain; class=java.io.InputStream; charset=UTF-8",
"text/html; document=fragment; class=java.io.InputStream; charset=US-ASCII",
"text/plain; class=java.nio.ByteBuffer; charset=UTF-16LE",
"text/plain; class=\"[B\"; charset=ISO-8859-1",
"text/html; document=all; class=java.io.InputStream; charset=UTF-16BE",
"text/html; document=all; class=java.nio.ByteBuffer; charset=UTF-16BE",
"text/unknown; class=java.lang.String",
"text/plain; class=java.lang.Object",
"text/html; document=all; class=java.nio.ByteBuffer; charset=US-ASCII",
"text/html; document=fragment; class=java.io.InputStream; charset=windows-1252",
"text/html; class=java.lang.Object; charset=unicode",
"text/html; document=all; class=java.nio.ByteBuffer; charset=UTF-8",
"unknown/flavor; class=java.lang.Object",
"text/html; document=fragment; class=java.io.InputStream; charset=UTF-8",
"text/html; document=fragment; class=java.io.InputStream; charset=ISO-8859-1",
"text/plain; class=java.io.Reader",
"text/html; document=selection; class=java.io.InputStream; charset=UTF-16LE",
"text/html; document=selection; class=java.nio.ByteBuffer; charset=windows-1252",
"text/html; document=all; class=\"[B\"; charset=US-ASCII",
"text/html; document=all; class=\"[B\"; charset=UTF-16LE",
"text/html; document=fragment; class=java.lang.String; charset=Unicode",
"text/plain; class=\"[C\"; charset=Unicode",
"text/html; document=fragment; class=java.io.InputStream; charset=UTF-16LE"
};
// We have to use a LinkedHashSet as this bug is dependent on the order of the entries in the set.
// Normally SunClipboard uses a HashSet which makes it difficult to replicate the test reliably.
final Set<DataFlavor> flavorSet = new LinkedHashSet<>(32);
for (String mime : mimes) {
flavorSet.add(new DataFlavor(mime));
}
// This will throw an IllegalArgumentException.
DataTransferer.setToSortedDataFlavorArray(flavorSet);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
-Djava.util.Arrays.useLegacyMergeSort=true as a JVM parameter will use the legacy sort and avoids the TimSort which performs this validation.
- duplicates
-
JDK-8078376 JTextComponent.paste: Comparison method violates contract?
-
- Closed
-
-
JDK-8130242 DataFlavorComparator transitivity exception
-
- Resolved
-
- relates to
-
JDK-8130242 DataFlavorComparator transitivity exception
-
- Resolved
-