Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8210311

IllegalArgumentException in CookieManager - Comparison method violates its general contract

    XMLWordPrintable

Details

    • b12
    • generic
    • generic

    Description

      ADDITIONAL SYSTEM INFORMATION :
      We've seen the crash on Windows 10 and macOS 10.13

      A DESCRIPTION OF THE PROBLEM :
      We've had this crash multiple times in our application:

      java.lang.IllegalArgumentException: Comparison method violates its general contract!
      at java.util.TimSort.mergeHi(TimSort.java:899) ~[?:1.8.0_161]
      at java.util.TimSort.mergeAt(TimSort.java:516) ~[?:1.8.0_161]
      at java.util.TimSort.mergeForceCollapse(TimSort.java:457) ~[?:1.8.0_161]
      at java.util.TimSort.sort(TimSort.java:254) ~[?:1.8.0_161]
      at java.util.Arrays.sort(Arrays.java:1512) ~[?:1.8.0_161]
      at java.util.ArrayList.sort(ArrayList.java:1462) ~[?:1.8.0_161]
      at java.util.Collections.sort(Collections.java:175) ~[?:1.8.0_161]
      at java.net.CookieManager.sortByPath(CookieManager.java:412) ~[?:1.8.0_161]
      at java.net.CookieManager.get(CookieManager.java:246) ~[?:1.8.0_161]

      While we've not been able to suitable data into the CookieManager to reproduce this crash, we have provided a test program that demonstrates the problem

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      I have written a test class that demonstrates that sorting cookies with the CookiePathComparator can cause a crash. It uses a dummy HttpCookie that implements the getName() and getPath() methods as required by the comparator, and I have copied the implementation of CookiePathComparator



      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      No crash
      ACTUAL -
      Crash

      ---------- BEGIN SOURCE ----------
      package seo.spider.unit;

      import java.util.Comparator;
      import java.util.List;
      import java.util.stream.Collectors;
      import java.util.stream.Stream;

      public class JavaBug
      {
          public static void main(
              final String[] args)
          {
              // This list in this order causes the crash.
              final List<HttpCookieDummy> cookies = Stream.of("charlie/alfa/", "charlie/", "india/echo/", "foxtrot/echo/", "hotel/charlie/", "alfa/", "golf/india/", "golf/", "echo/golf/", "bravo/india/", "golf/alfa/", "echo/alfa/", "bravo/alfa/", "foxtrot/golf/", "golf/golf/", "delta/golf/", "juliett/golf/", "juliett/charlie/", "hotel/echo/", "echo/charlie/", "india/golf/", "delta/echo/", "india/", "india/charlie/", "india/alfa/", "charlie/charlie/", "delta/charlie/", "bravo/charlie/", "echo/india/", "delta/india/", "delta/alfa/", "foxtrot/charlie/", "hotel/alfa/", "foxtrot/alfa/", "charlie/golf/", "echo/echo/", "juliett/india/", "golf/charlie/", "juliett/echo/", "charlie/india/", "bravo/golf/", "echo/", "india/india/", "hotel/india/", "foxtrot/india/", "juliett/alfa/", "hotel/golf/", "bravo/echo/", "golf/echo/", "charlie/echo/")
                  .map(HttpCookieDummy::new)
                  .collect(Collectors.toList());

              cookies.sort(new HttpCookieDummyComparator());
          }

          // Dummies enough of the HttpCookie API to demonstrate this bug
          private static class HttpCookieDummy
          {
              private final String mPath;

              public HttpCookieDummy(final String path)
              {
                  mPath = path;
              }

              public String getName()
              {
                  return "name";
              }

              public String getPath()
              {
                  return mPath;
              }
          }

          // Copied from CookieManager.java
          private static class HttpCookieDummyComparator implements Comparator<HttpCookieDummy>
          {
              public int compare(HttpCookieDummy c1, HttpCookieDummy c2) {
                  if (c1 == c2) return 0;
                  if (c1 == null) return -1;
                  if (c2 == null) return 1;

                  // path rule only applies to the cookies with same name
                  if (!c1.getName().equals(c2.getName())) return 0;

                  // those with more specific Path attributes precede those with less specific
                  if (c1.getPath().startsWith(c2.getPath()))
                      return -1;
                  else if (c2.getPath().startsWith(c1.getPath()))
                      return 1;
                  else
                      return 0;
              }
          }
      }

      ---------- END SOURCE ----------

      FREQUENCY : occasionally


      Attachments

        Issue Links

          Activity

            People

              michaelm Michael McMahon
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: