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

hashCode() implementation for java.awt.SystemColor / java.awt.Color is flawed

    • generic
    • generic

      SYNOPSIS
      --------
      hashCode() implementation for java.awt.SystemColor / java.awt.Color is flawed

      OPERATING SYSTEM
      ----------------
      All

      FULL JDK VERSION
      ----------------
      All Java 6 releases are affected by the Java 6 issue
      All Java 7 builds are affected by the Java 7 issue

      PROBLEM DESCRIPTION from LICENSEE
      ---------------------------------
      The results of calling hashCode() on the static SystemColor instances defined in the SystemColor class break the hashCode() contract on Java 6, and Java 7, for different reasons on each release.

      In the API documentation for java.lang.Object, the general contract for hashCode() states:

      * Whenever it is invoked on the same object more than once during an
        execution of a Java application, the hashCode method must consistently
        return the same integer, provided no information used in equals
        comparisons on the object is modified. This integer need not remain
        consistent from one execution of an application to another execution
        of the same application.

      * If two objects are equal according to the equals(Object) method, then
        calling the hashCode method on each of the two objects must produce
        the same integer result.

      On Java 6, SystemColor.hashCode() breaks the second part of the contract. Two SystemColor instances can be equal even though their hash codes are different.

      That problem is fixed on Java 7, where the integer returned by SystemColor.hashCode() is identical to the integer returned by SystemColor.getRGB(). Both calls actually invoke the methods in the parent Color class, unlike Java 6 where hashCode() is overridden in the SystemColor class. However, this causes another problem. Consider the following statement in the SystemColor API documentation:

         For systems which support the dynamic update of the system colors
         (when the user changes the colors) the actual RGB values of these
         symbolic colors will also change dynamically.

      Since hashCode() is returning the RGB colour value, and that RGB colour value can change dynamically, it follows that the return value of hashCode() can also change during the execution of a Java application, thus violating part 1 of the hashCode() contract. This is proved by the second testcase provided below.

      REPRODUCTION INSTRUCTIONS - JAVA 6 ISSUE
      ----------------------------------------
      1. Compile and run SystemColorTest1.java (attached)
      2. Observe the following behaviour on Java 6:

         Found equals() / hashCode() contract violation:
         Compared java.awt.SystemColor[i=14] to java.awt.SystemColor[i=1]
         java.awt.SystemColor[i=14] hashcode = 14
         java.awt.SystemColor[i=1] hashcode = 1
         java.awt.SystemColor[i=14] RGB value = -13410648
         java.awt.SystemColor[i=1] RGB value = -13410648

         Test failed!

      3. Observe the following result on Java 7, which represents the expected
         behaviour:

         Test passed!

      REPRODUCTION INSTRUCTIONS - JAVA 7 ISSUE
      ----------------------------------------
      1. Compile and run SystemColorTest2.java (attached)

      2. While the testcase is running, change the colour of the OS desktop
         (for example, on Windows, simply right click the desktop and change
         the setting in Properties->Desktop->Color)

      3. Observe a result similar to the following with Java 7 (the integers
         involved depend on the colours you change to/from):

         hashCode() return value changed from -16777216 to -65536
         Test Failed!

      4. Observer the following result with Java 6 (the expected behaviour):

         Test Passed!


      TESTCASE SOURCE (ATTACHED)
      ------------------------------
      SystemColorTest1 - JDK 6 Issue.
      SystemColorTest2 - JDK 7 Issue.

          Loading...
          Uploaded image for project: 'JDK'
          1. JDK
          2. JDK-6962773

          hashCode() implementation for java.awt.SystemColor / java.awt.Color is flawed

            • generic
            • generic

              SYNOPSIS
              --------
              hashCode() implementation for java.awt.SystemColor / java.awt.Color is flawed

              OPERATING SYSTEM
              ----------------
              All

              FULL JDK VERSION
              ----------------
              All Java 6 releases are affected by the Java 6 issue
              All Java 7 builds are affected by the Java 7 issue

              PROBLEM DESCRIPTION from LICENSEE
              ---------------------------------
              The results of calling hashCode() on the static SystemColor instances defined in the SystemColor class break the hashCode() contract on Java 6, and Java 7, for different reasons on each release.

              In the API documentation for java.lang.Object, the general contract for hashCode() states:

              * Whenever it is invoked on the same object more than once during an
                execution of a Java application, the hashCode method must consistently
                return the same integer, provided no information used in equals
                comparisons on the object is modified. This integer need not remain
                consistent from one execution of an application to another execution
                of the same application.

              * If two objects are equal according to the equals(Object) method, then
                calling the hashCode method on each of the two objects must produce
                the same integer result.

              On Java 6, SystemColor.hashCode() breaks the second part of the contract. Two SystemColor instances can be equal even though their hash codes are different.

              That problem is fixed on Java 7, where the integer returned by SystemColor.hashCode() is identical to the integer returned by SystemColor.getRGB(). Both calls actually invoke the methods in the parent Color class, unlike Java 6 where hashCode() is overridden in the SystemColor class. However, this causes another problem. Consider the following statement in the SystemColor API documentation:

                 For systems which support the dynamic update of the system colors
                 (when the user changes the colors) the actual RGB values of these
                 symbolic colors will also change dynamically.

              Since hashCode() is returning the RGB colour value, and that RGB colour value can change dynamically, it follows that the return value of hashCode() can also change during the execution of a Java application, thus violating part 1 of the hashCode() contract. This is proved by the second testcase provided below.

              REPRODUCTION INSTRUCTIONS - JAVA 6 ISSUE
              ----------------------------------------
              1. Compile and run SystemColorTest1.java (attached)
              2. Observe the following behaviour on Java 6:

                 Found equals() / hashCode() contract violation:
                 Compared java.awt.SystemColor[i=14] to java.awt.SystemColor[i=1]
                 java.awt.SystemColor[i=14] hashcode = 14
                 java.awt.SystemColor[i=1] hashcode = 1
                 java.awt.SystemColor[i=14] RGB value = -13410648
                 java.awt.SystemColor[i=1] RGB value = -13410648

                 Test failed!

              3. Observe the following result on Java 7, which represents the expected
                 behaviour:

                 Test passed!

              REPRODUCTION INSTRUCTIONS - JAVA 7 ISSUE
              ----------------------------------------
              1. Compile and run SystemColorTest2.java (attached)

              2. While the testcase is running, change the colour of the OS desktop
                 (for example, on Windows, simply right click the desktop and change
                 the setting in Properties->Desktop->Color)

              3. Observe a result similar to the following with Java 7 (the integers
                 involved depend on the colours you change to/from):

                 hashCode() return value changed from -16777216 to -65536
                 Test Failed!

              4. Observer the following result with Java 6 (the expected behaviour):

                 Test Passed!


              TESTCASE SOURCE (ATTACHED)
              ------------------------------
              SystemColorTest1 - JDK 6 Issue.
              SystemColorTest2 - JDK 7 Issue.

                    Unassigned Unassigned
                    dkorbel David Korbel (Inactive)
                    Votes:
                    0 Vote for this issue
                    Watchers:
                    1 Start watching this issue

                      Created:
                      Updated:
                      Imported:
                      Indexed:

                        Unassigned Unassigned
                        dkorbel David Korbel (Inactive)
                        Votes:
                        0 Vote for this issue
                        Watchers:
                        1 Start watching this issue

                          Created:
                          Updated:
                          Imported:
                          Indexed: