JDK-8058973 : NullPointerException from ICC_Profile.getInstance() in multi-thread application
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 7u65,7u80,8u20,9
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: x86
  • Submitted: 2014-09-22
  • Updated: 2020-11-13
  • Resolved: 2020-11-13
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdResolved
Related Reports
Duplicate :  
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_12"
Java(TM) SE Runtime Environment (build 1.6.0_12-b04)
Java HotSpot(TM) Server VM (build 11.2-b01, mixed mode)

The bug has been observed with a few versions of Java 6 and 7.

ADDITIONAL OS VERSION INFORMATION :
Linux samoa 2.6.31-23-generic-pae #75-Ubuntu SMP Fri Mar 18 19:14:10 UTC 2011 i686 GNU/Linux

The bug has been observed on a couple versions of Windows as well.

A DESCRIPTION OF THE PROBLEM :
Loading ICC color profiles from multiple threads sometimes triggers a null pointer exception inside the JRE's ICC_Profile class.

This bug report is similar to (but not a duplicate of) this one:
  JDK-6986863 : ProfileDeferralMgr throwing ConcurrentModificationException

Ultimately, ProfileDeferralMgr has non-final static fields that are not synchronized and one of them is a container that's not using a thread safe class. All the methods on ProfileDeferralMgr should probably be synchronized. The call to ProfileDeferralMgr.unregisterDeferral() should be removed from ICC_Profile.finalize(), and any other finalizers, since a profile won't get gc'ed if it's referenced from the static list in ProfileDeferralMgr.

Also, JDK-6793818 seems to be the reason that all of the standard profiles are lazy loaded with Java 7, where only the sRGB profile was lazy loaded with Java 6. The chance of hitting this bug with 7 is probably greater than with 6.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Load the JRE's sRGB color profile, then on two or more threads load any non-JRE color profile. There is a race condition between the threads when they execute the lazy loading of the standard profiles inside ICC_Profile and ProfileDeferralMgr.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Calls to ICC_Profile.getInstance() should be multi-thread safe, especially when loading profiles from a byte array or stream (as opposed to loading the standard JRE profiles that are cached inside ICC_Profile).
ACTUAL -
Occassional null pointer exceptions in threads that load ICC profiles.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "Thread-0" java.lang.NullPointerException
	at java.awt.color.ICC_Profile.activateDeferredProfile(ICC_Profile.java:1052)
	at java.awt.color.ICC_Profile$1.activate(ICC_Profile.java:723)
	at sun.awt.color.ProfileDeferralMgr.activateProfiles(ProfileDeferralMgr.java:75)
	at java.awt.color.ICC_Profile.getInstance(ICC_Profile.java:756)
	at java.awt.color.ICC_Profile.getInstance(ICC_Profile.java:976)
	at java.awt.color.ICC_Profile.getInstance(ICC_Profile.java:941)
	at com.blah.ProfileReader$1.run(ProfileReader2.java:38)


REPRODUCIBILITY :
This bug can be reproduced occasionally.

---------- BEGIN SOURCE ----------
package com.blah;

import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicInteger;

// This tester fails about 1 in 4 runs.
public class ProfileReader {

	public static void main(String[] args) throws InterruptedException {

		// This puts a deferred load in the queue
		ICC_Profile.getInstance(ColorSpace.CS_sRGB);

		List<Thread> threads = new ArrayList<Thread>();

		final AtomicInteger successCount = new AtomicInteger();

		int numThreads = 100;

		final CyclicBarrier barrier = new CyclicBarrier(numThreads);

		for (int i = 0; i < numThreads; i++) {

			Thread thread = new Thread() {
				@Override
				public void run() {

					try {
						barrier.await();

						// This loads some other profile, triggering the delayed load of sRGB
						ICC_Profile.getInstance("/usr/lib/jdk1.6.0_12/jre/lib/cmm/GRAY.pf");

						successCount.incrementAndGet();
					} catch (InterruptedException e) {
						e.printStackTrace();
					} catch (BrokenBarrierException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			};

			thread.start();
			threads.add(thread);
		}

		for (Thread thread : threads) {
			thread.join();
		}

		System.out.println("Profile load failures = " + (numThreads - successCount.get()));
	}
}

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

CUSTOMER SUBMITTED WORKAROUND :
In application code synchronize all calls to ICC_Profile.getInstance(). This isn't a complete solution, since some calls to ICC_Profile.getInstance() come in from elsewhere in the JRE, as shown in bug "JDK-6986863".


Comments
Actually, I tried on windows7 since OS "generic" was mentioned and there it does not happen if run once with jdk9151. However, running 10-12 times, it seems to happen once or twice.
04-03-2017

I looked at the log of changes to ICC_Profile.java and did not find anything that might have fixed it. So I tried. And I reproduced it immediately with JDK9 b151 on Linux x64 ~/jdk9b151/bin/java ProfileReader Exception in thread "Thread-3" java.lang.NullPointerException at java.desktop/java.awt.color.ICC_Profile.activateDeferredProfile(ICC_Profile.java:1092) at java.desktop/java.awt.color.ICC_Profile$1.activate(ICC_Profile.java:745) at java.desktop/sun.java2d.cmm.ProfileDeferralMgr.activateProfiles(ProfileDeferralMgr.java:95) at java.desktop/java.awt.color.ICC_Profile.getInstance(ICC_Profile.java:778) at java.desktop/java.awt.color.ICC_Profile.getInstance(ICC_Profile.java:1020) at java.desktop/java.awt.color.ICC_Profile.getInstance(ICC_Profile.java:985) at ProfileReader$1.run(ProfileReader.java:37) Exception in thread "Thread-2" java.util.ConcurrentModificationException at java.base/java.util.Vector$Itr.checkForComodification(Vector.java:1294) at java.base/java.util.Vector$Itr.next(Vector.java:1250) at java.desktop/sun.java2d.cmm.ProfileDeferralMgr.activateProfiles(ProfileDeferralMgr.java:93) at java.desktop/java.awt.color.ICC_Profile.getInstance(ICC_Profile.java:778) at java.desktop/java.awt.color.ICC_Profile.getInstance(ICC_Profile.java:1020) at java.desktop/java.awt.color.ICC_Profile.getInstance(ICC_Profile.java:985) at ProfileReader$1.run(ProfileReader.java:37) Profile load failures = 2
03-03-2017

I am not able to reproduce this with jdk9. I am getting Profile load failures = 0 when I run with jdk9
02-03-2017

Inputs from the submitter: With jre1.7.0_67 I got the following error on the third run of my test code: Exception in thread "Thread-99" java.util.ConcurrentModificationException at java.util.Vector$Itr.checkForComodification(Unknown Source) at java.util.Vector$Itr.next(Unknown Source) at sun.java2d.cmm.ProfileDeferralMgr.activateProfiles(Unknown Source) at java.awt.color.ICC_Profile.getInstance(Unknown Source) at java.awt.color.ICC_Profile.getInstance(Unknown Source) at java.awt.color.ICC_Profile.getInstance(Unknown Source) at com.lifetouch.lti.color.ProfileReader2$1.run(ProfileReader2.java:49) With jre1.8.0_20 I got the following error on the second run of the test code: Exception in thread "Thread-0" java.lang.NullPointerException at java.awt.color.ICC_Profile.activateDeferredProfile(ICC_Profile.java:1090) at java.awt.color.ICC_Profile$1.activate(ICC_Profile.java:744) at sun.java2d.cmm.ProfileDeferralMgr.activateProfiles(ProfileDeferralMgr.java:95) at java.awt.color.ICC_Profile.getInstance(ICC_Profile.java:777) at java.awt.color.ICC_Profile.getInstance(ICC_Profile.java:1017) at java.awt.color.ICC_Profile.getInstance(ICC_Profile.java:982) at com.lifetouch.lti.color.ProfileReader2$1.run(ProfileReader2.java:49) So, the bug is still there with the latest, Java versions.
24-09-2014

One run I've got both NPE together with ConcurrentModificationException with 7u80
23-09-2014

Reproduced rarely.
23-09-2014

Mail was sent to submitter requesting more information.
23-09-2014