5

This is a tough one. A customer has sent me, via a crash report, this stack trace. It has no mention of my app's classes, so I'm perplexed as to where to start looking.

My app is a commercial desktop app. Crash reports are anonymous, so I can't easily obtain more information about the crash.

EDIT: Some Googling and thread-following makes me conclude that it is a sporadic problem in Java 1.7. Looking for a solution...

How can I proceed in debugging this?

java.lang.IllegalArgumentException: Comparison method violates its general contract!
        at java.util.TimSort.mergeHi(TimSort.java:868)
        at java.util.TimSort.mergeAt(TimSort.java:485)
        at java.util.TimSort.mergeCollapse(TimSort.java:410)
        at java.util.TimSort.sort(TimSort.java:214)
        at java.util.TimSort.sort(TimSort.java:173)
        at java.util.Arrays.sort(Arrays.java:659)
        at java.util.Collections.sort(Collections.java:217)
        at javax.swing.SortingFocusTraversalPolicy.enumerateAndSortCycle(SortingFocusTraversalPolicy.java:136)
        at javax.swing.SortingFocusTraversalPolicy.getFocusTraversalCycle(SortingFocusTraversalPolicy.java:110)
        at javax.swing.SortingFocusTraversalPolicy.getFirstComponent(SortingFocusTraversalPolicy.java:435)
        at javax.swing.LayoutFocusTraversalPolicy.getFirstComponent(LayoutFocusTraversalPolicy.java:166)
        at javax.swing.DefaultFocusManager.getFirstComponent(DefaultFocusManager.java:120)
        at javax.swing.LegacyGlueFocusTraversalPolicy.getFirstComponent(LegacyGlueFocusTraversalPolicy.java:132)
        at javax.swing.LegacyGlueFocusTraversalPolicy.getDefaultComponent(LegacyGlueFocusTraversalPolicy.java:150)
        at java.awt.FocusTraversalPolicy.getInitialComponent(FocusTraversalPolicy.java:169)
        at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:380)
        at java.awt.Component.dispatchEventImpl(Component.java:4731)
        at java.awt.Container.dispatchEventImpl(Container.java:2287)
        at java.awt.Window.dispatchEventImpl(Window.java:2719)
        at java.awt.Component.dispatchEvent(Component.java:4687)
        at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:723)
        at java.awt.EventQueue.access$200(EventQueue.java:103)
        at java.awt.EventQueue$3.run(EventQueue.java:682)
        at java.awt.EventQueue$3.run(EventQueue.java:680)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
        at java.awt.EventQueue$4.run(EventQueue.java:696)
        at java.awt.EventQueue$4.run(EventQueue.java:694)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:693)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
Steve McLeod
  • 51,737
  • 47
  • 128
  • 184
  • 3
    I found a known bug for this in Oracle's Java bug tracker: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6923200 They've marked it closed as cannot reproduce. That doesn't make me happy. – Steve McLeod Jan 22 '13 at 05:28
  • http://stackoverflow.com/questions/7849539/comparison-method-violates-its-general-contract-java-7-only – Nikolay Kuznetsov Jan 22 '13 at 05:31
  • Java 1.7. The problem never occurred when Java 1.6, and we're now targetting 1.7. – Steve McLeod Jan 22 '13 at 05:31
  • @Nikolay Kuznetsov Thanks for those links. Although the first lines of the stack trace are the same as mine, they seem to be tracked directly to user code. In my case, unfortunately, all I have are the inner workings of Swing. – Steve McLeod Jan 22 '13 at 05:35
  • 1
    "you can use the new system property, `java.util.Arrays.useLegacyMergeSort`, to restore previous mergesort behavior." – Nikolay Kuznetsov Jan 22 '13 at 05:37
  • 2
    If you provide any implementation of `Comparator` to Swing, the problem is in your `Comparator` implementation. It won't appear in the stack trace because the error is being detected when merging two runs. It is the ordering of the runs being incorrect (caused by a bad Comparator) that is being detected, at some time _after_ the (your?) Comparator is used. – Jim Garrison Jan 22 '13 at 06:12
  • @Jim Garrison, no it is not a comparator I'm supplying. It is something internal to Swing. – Steve McLeod Jan 22 '13 at 12:35
  • you might have spared yourself the trouble of having been closed by adding the Swing tag ;-) Just sayin' ... +1, btw, good to know that catch! – kleopatra Jan 22 '13 at 13:56
  • 3
    Similar problem here: http://stackoverflow.com/questions/13575224/comparison-method-violates-its-general-contract-timsort-and-gridlayout You can try adding -Djava.util.Arrays.useLegacyMergeSort=true to the application parameters as detailed there. – Andrei Fierbinteanu Jan 22 '13 at 08:16

4 Answers4

3

As pointed out elsewhere, the items in the collection being sorted (which may or may not include your own classes, can't tell from the stack trace) violate the comparison contract.

During a transition from Java 6 to Java 7, the default sorting implementation changed to TimSort. One of the impacts of this is that the new sort is more strict about the comparison contract, so you (or perhaps, Swing) may have been getting away with it for a long time, but no longer.

If you can't fix the problem with the comparison contract, you can roll back to use the Java 6 style sorting by booting your application with the property

-Djava.util.Arrays.useLegacyMergeSort=true

as detailed in the Java 7 release notes, compatibility section.

sharakan
  • 6,821
  • 1
  • 34
  • 61
1

java.lang.IllegalArgumentException: Comparison method violates its general contract!

I suspect this means that the Comparison method is not a total ordering. As in, it violates one of the three properties ALL sorting methods must have:

1) Reflexivity - if x == y, y == x. If x > y, y < x.

2) Identity: x == x.

3) Transistivity: if x > y and y > z, x > z.

The comparison method needs to be fixed to obey these laws. How to do that will remain to be seen when you look at it :)

Patashu
  • 21,443
  • 3
  • 45
  • 53
0

As per rules of new Comparable Contract given rules must always be true for compareTo function. These rules were introduced in JDK 7 -

  • The implementor must ensure that sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y. (This implies that compare(x, y) must throw an exception if and only if compare(y, x) throws an exception.

    • The implementor must also ensure that the relation is transitive: ((compare(x, y) > 0, (compare(y, z) > 0)) implies compare(x, z) > 0

    • Finally, the implementor must ensure that compare(x, y)==0 implies that sgn(compare(x, z)) == sgn(compare(y, z)) for all z.

Now, as obvious as it may seem that these rules will always be abided by, we have many exceptions.

Consider the case - Implementation of compareTo function in code -

   return (int) (y - x)

where x & y are double. Let's consider x = 2, y = 1.6

The values satisfy rules 1 and 2 but for rule 3, consider z = 2.4

compare(x,y) = int(1.6-2)   = int(-0.4) = 0
compare(x,z) = int(2.4-2)   = int(0.4) = 0
compare(y,z) = int(2.4-1.6) = int(0.8) = 1.

Hence, violating the contract.

Kingsley
  • 14,398
  • 5
  • 31
  • 53
Satakshi Pandey
  • 234
  • 4
  • 9
0

This is a documented bug introduced in Java by Oracle. It has now been fixed.

The workaround I've been using was to set a relevant system property immediately after my app launches:

System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");

The issue was fixed in Java 8u40, so the workaround is no longer necessary.

See: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8048887

Steve McLeod
  • 51,737
  • 47
  • 128
  • 184