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

java.awt.color.ICC_ColorSpace is not thread-safe

    XMLWordPrintable

    Details

    • Subcomponent:
      2d
    • Resolved In Build:
      b24
    • CPU:
      generic
    • OS:
      generic

      Description

      A DESCRIPTION OF THE PROBLEM :
      Calling fromRGB or toRGB (or any other conversion functions) isn't thread safe in ICC_ColorSpace. There is a one-time init at the start of each function that isn't guarded by any lock. The code almost gets away with it by using transients, but the transient lookup table is set before a call to setComponentScaling which occasionally causes NullPointerExceptions when calling conversion functions from multiple threads.

      An easy solution would be to mark ICC_ColorSpace as not-thread-safe, but the issue is that java.awt.color.ColorSpace.getInstance returns lazily-initialized singletons of this class. It seems like the current design requires either returning new instances to each caller or just synchronizing the ColorSpace class.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      You can run the repro

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Prints infinitely

      Try 1
      OK
      Try 2
      OK
      ACTUAL -
      Try 43
      java.lang.NullPointerException
      at java.desktop/java.awt.color.ICC_ColorSpace.toRGB(ICC_ColorSpace.java:183)
      at Repro.lambda$test$0(Repro.java:20)
      at java.base/java.lang.Thread.run(Thread.java:832)

      In less than 10 seconds or so.

      ---------- BEGIN SOURCE ----------
      import java.awt.color.*;
      import java.util.concurrent.*;

      public final class Repro {
        public static final void main(String[] args) throws Throwable {
          for (int i = 0; true; i++) {
            System.err.println("Try " + i);
            test(new ICC_ColorSpace(ICC_Profile.getInstance(ColorSpace.CS_sRGB)));
          }
        }

        public static void test(final ColorSpace cs) throws Throwable {
          Thread[] ts = new Thread[10];
          final CountDownLatch latch = new CountDownLatch(ts.length);
          for (int i = 0; i < ts.length; i++) {
            ts[i] =
                new Thread(
                    () -> {
                      latch.countDown();
                      try {
                        latch.await();
                      } catch (InterruptedException ex) {
                      }
                      try {
                        cs.toRGB(new float[3]);
                      } catch (Throwable t) {
                        t.printStackTrace();
                        System.exit(1);
                      }
                    });
          }
          for (Thread t : ts) {
            t.start();
          }
          for (Thread t : ts) {
            t.join();
          }
          System.err.println("OK");
        }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Since these are static inits, you could just call fromRGB/toRGB/etc in a synchronized context before using the color spaces - or alternatively, always synchronize calls to conversion routines yourself.

      FREQUENCY : rarely


        Attachments

          Issue Links

            Activity

              People

              Assignee:
              serb Sergey Bylokhov
              Reporter:
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: