Skip to content

Commit 2cad836

Browse files
committed
8255575: java.awt.color.ICC_ColorSpace is not thread-safe
Reviewed-by: prr
1 parent a53b12d commit 2cad836

File tree

2 files changed

+178
-68
lines changed

2 files changed

+178
-68
lines changed

src/java.desktop/share/classes/java/awt/color/ICC_ColorSpace.java

Lines changed: 76 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,10 @@ public class ICC_ColorSpace extends ColorSpace {
115115
private boolean needScaleInit = true;
116116

117117
// {to,from}{RGB,CIEXYZ} methods create and cache these when needed
118-
private transient ColorTransform this2srgb;
119-
private transient ColorTransform srgb2this;
120-
private transient ColorTransform this2xyz;
121-
private transient ColorTransform xyz2this;
118+
private transient volatile ColorTransform this2srgb;
119+
private transient volatile ColorTransform srgb2this;
120+
private transient volatile ColorTransform this2xyz;
121+
private transient volatile ColorTransform xyz2this;
122122

123123
/**
124124
* Constructs a new {@code ICC_ColorSpace} from an {@code ICC_Profile}
@@ -193,20 +193,22 @@ public ICC_Profile getProfile() {
193193
* @throws ArrayIndexOutOfBoundsException if array length is not at least
194194
* the number of components in this {@code ColorSpace}
195195
*/
196-
public float[] toRGB (float[] colorvalue) {
197-
196+
public float[] toRGB(float[] colorvalue) {
198197
if (this2srgb == null) {
199-
ColorTransform[] transformList = new ColorTransform [2];
200-
ICC_ColorSpace srgbCS =
201-
(ICC_ColorSpace) ColorSpace.getInstance (CS_sRGB);
202-
PCMM mdl = CMSManager.getModule();
203-
transformList[0] = mdl.createTransform(
204-
thisProfile, ColorTransform.Any, ColorTransform.In);
205-
transformList[1] = mdl.createTransform(
206-
srgbCS.getProfile(), ColorTransform.Any, ColorTransform.Out);
207-
this2srgb = mdl.createTransform(transformList);
208-
if (needScaleInit) {
209-
setComponentScaling();
198+
synchronized (this) {
199+
if (this2srgb == null) {
200+
ColorTransform[] transforms = new ColorTransform[2];
201+
var srgb = (ICC_ColorSpace) getInstance(CS_sRGB);
202+
PCMM mdl = CMSManager.getModule();
203+
transforms[0] = mdl.createTransform(thisProfile,
204+
ColorTransform.Any, ColorTransform.In);
205+
transforms[1] = mdl.createTransform(srgb.getProfile(),
206+
ColorTransform.Any, ColorTransform.Out);
207+
if (needScaleInit) {
208+
setComponentScaling();
209+
}
210+
this2srgb = mdl.createTransform(transforms);
211+
}
210212
}
211213
}
212214

@@ -243,20 +245,22 @@ public float[] toRGB (float[] colorvalue) {
243245
* this {@code ColorSpace}
244246
* @throws ArrayIndexOutOfBoundsException if array length is not at least 3
245247
*/
246-
public float[] fromRGB(float[] rgbvalue) {
247-
248+
public float[] fromRGB(float[] rgbvalue) {
248249
if (srgb2this == null) {
249-
ColorTransform[] transformList = new ColorTransform [2];
250-
ICC_ColorSpace srgbCS =
251-
(ICC_ColorSpace) ColorSpace.getInstance (CS_sRGB);
252-
PCMM mdl = CMSManager.getModule();
253-
transformList[0] = mdl.createTransform(
254-
srgbCS.getProfile(), ColorTransform.Any, ColorTransform.In);
255-
transformList[1] = mdl.createTransform(
256-
thisProfile, ColorTransform.Any, ColorTransform.Out);
257-
srgb2this = mdl.createTransform(transformList);
258-
if (needScaleInit) {
259-
setComponentScaling();
250+
synchronized (this) {
251+
if (srgb2this == null) {
252+
ColorTransform[] transforms = new ColorTransform[2];
253+
var srgb = (ICC_ColorSpace) getInstance(CS_sRGB);
254+
PCMM mdl = CMSManager.getModule();
255+
transforms[0] = mdl.createTransform(srgb.getProfile(),
256+
ColorTransform.Any, ColorTransform.In);
257+
transforms[1] = mdl.createTransform(thisProfile,
258+
ColorTransform.Any, ColorTransform.Out);
259+
if (needScaleInit) {
260+
setComponentScaling();
261+
}
262+
srgb2this = mdl.createTransform(transforms);
263+
}
260264
}
261265
}
262266

@@ -373,26 +377,28 @@ public float[] fromRGB(float[] rgbvalue) {
373377
* @throws ArrayIndexOutOfBoundsException if array length is not at least
374378
* the number of components in this {@code ColorSpace}
375379
*/
376-
public float[] toCIEXYZ(float[] colorvalue) {
377-
380+
public float[] toCIEXYZ(float[] colorvalue) {
378381
if (this2xyz == null) {
379-
ColorTransform[] transformList = new ColorTransform [2];
380-
ICC_ColorSpace xyzCS =
381-
(ICC_ColorSpace) ColorSpace.getInstance (CS_CIEXYZ);
382-
PCMM mdl = CMSManager.getModule();
383-
try {
384-
transformList[0] = mdl.createTransform(
385-
thisProfile, ICC_Profile.icRelativeColorimetric,
386-
ColorTransform.In);
387-
} catch (CMMException e) {
388-
transformList[0] = mdl.createTransform(
389-
thisProfile, ColorTransform.Any, ColorTransform.In);
390-
}
391-
transformList[1] = mdl.createTransform(
392-
xyzCS.getProfile(), ColorTransform.Any, ColorTransform.Out);
393-
this2xyz = mdl.createTransform (transformList);
394-
if (needScaleInit) {
395-
setComponentScaling();
382+
synchronized (this) {
383+
if (this2xyz == null) {
384+
ColorTransform[] transforms = new ColorTransform[2];
385+
var xyz = (ICC_ColorSpace) getInstance(CS_CIEXYZ);
386+
PCMM mdl = CMSManager.getModule();
387+
try {
388+
transforms[0] = mdl.createTransform(thisProfile,
389+
ICC_Profile.icRelativeColorimetric,
390+
ColorTransform.In);
391+
} catch (CMMException e) {
392+
transforms[0] = mdl.createTransform(thisProfile,
393+
ColorTransform.Any, ColorTransform.In);
394+
}
395+
transforms[1] = mdl.createTransform(xyz.getProfile(),
396+
ColorTransform.Any, ColorTransform.Out);
397+
if (needScaleInit) {
398+
setComponentScaling();
399+
}
400+
this2xyz = mdl.createTransform(transforms);
401+
}
396402
}
397403
}
398404

@@ -511,26 +517,28 @@ public float[] toCIEXYZ(float[] colorvalue) {
511517
* this {@code ColorSpace}
512518
* @throws ArrayIndexOutOfBoundsException if array length is not at least 3
513519
*/
514-
public float[] fromCIEXYZ(float[] colorvalue) {
515-
520+
public float[] fromCIEXYZ(float[] colorvalue) {
516521
if (xyz2this == null) {
517-
ColorTransform[] transformList = new ColorTransform [2];
518-
ICC_ColorSpace xyzCS =
519-
(ICC_ColorSpace) ColorSpace.getInstance (CS_CIEXYZ);
520-
PCMM mdl = CMSManager.getModule();
521-
transformList[0] = mdl.createTransform (
522-
xyzCS.getProfile(), ColorTransform.Any, ColorTransform.In);
523-
try {
524-
transformList[1] = mdl.createTransform(
525-
thisProfile, ICC_Profile.icRelativeColorimetric,
526-
ColorTransform.Out);
527-
} catch (CMMException e) {
528-
transformList[1] = CMSManager.getModule().createTransform(
529-
thisProfile, ColorTransform.Any, ColorTransform.Out);
530-
}
531-
xyz2this = mdl.createTransform(transformList);
532-
if (needScaleInit) {
533-
setComponentScaling();
522+
synchronized (this) {
523+
if (xyz2this == null) {
524+
ColorTransform[] transforms = new ColorTransform[2];
525+
var xyz = (ICC_ColorSpace) getInstance(CS_CIEXYZ);
526+
PCMM mdl = CMSManager.getModule();
527+
transforms[0] = mdl.createTransform(xyz.getProfile(),
528+
ColorTransform.Any, ColorTransform.In);
529+
try {
530+
transforms[1] = mdl.createTransform(thisProfile,
531+
ICC_Profile.icRelativeColorimetric,
532+
ColorTransform.Out);
533+
} catch (CMMException e) {
534+
transforms[1] = mdl.createTransform(thisProfile,
535+
ColorTransform.Any, ColorTransform.Out);
536+
}
537+
if (needScaleInit) {
538+
setComponentScaling();
539+
}
540+
xyz2this = mdl.createTransform(transforms);
541+
}
534542
}
535543
}
536544

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import java.awt.color.ColorSpace;
25+
import java.awt.color.ICC_ColorSpace;
26+
import java.awt.color.ICC_Profile;
27+
import java.util.concurrent.CountDownLatch;
28+
import java.util.concurrent.TimeUnit;
29+
30+
/**
31+
* @test
32+
* @bug 8254370
33+
* @summary Verifies MT safety of ICC_ColorSpace#To/From methods
34+
*/
35+
public final class MTICC_ColorSpaceToFrom {
36+
37+
private enum Method {
38+
FROM_RGB, FROM_XYZ, TO_RGB, TO_XYZ;
39+
}
40+
41+
static volatile long endtime;
42+
static volatile boolean failed;
43+
44+
public static void main(String[] args) throws Exception {
45+
ICC_Profile srgb = ICC_Profile.getInstance(ColorSpace.CS_sRGB);
46+
ICC_Profile gray = ICC_Profile.getInstance(ColorSpace.CS_GRAY);
47+
ICC_Profile xyz = ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ);
48+
ICC_Profile lrgb = ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB);
49+
ICC_Profile pycc = ICC_Profile.getInstance(ColorSpace.CS_PYCC);
50+
51+
// Will run the test no more than 15 seconds
52+
endtime = System.nanoTime() + TimeUnit.SECONDS.toNanos(10);
53+
for (int i = 0; i < 1000 && !isComplete(); i++) {
54+
for (Method method : new Method[]{Method.FROM_RGB, Method.FROM_XYZ,
55+
Method.TO_RGB, Method.TO_XYZ}) {
56+
test(new ICC_ColorSpace(srgb), method);
57+
test(new ICC_ColorSpace(gray), method);
58+
test(new ICC_ColorSpace(xyz), method);
59+
test(new ICC_ColorSpace(lrgb), method);
60+
test(new ICC_ColorSpace(pycc), method);
61+
}
62+
}
63+
if (failed) {
64+
throw new RuntimeException();
65+
}
66+
}
67+
68+
private static void test(ColorSpace cs, Method method) throws Exception {
69+
Thread[] ts = new Thread[10];
70+
CountDownLatch latch = new CountDownLatch(ts.length);
71+
for (int i = 0; i < ts.length; i++) {
72+
ts[i] = new Thread(() -> {
73+
latch.countDown();
74+
try {
75+
latch.await();
76+
} catch (InterruptedException ex) {
77+
}
78+
try {
79+
switch (method) {
80+
case TO_RGB -> cs.toRGB(new float[3]);
81+
case FROM_RGB -> cs.fromRGB(new float[3]);
82+
case TO_XYZ -> cs.toCIEXYZ(new float[3]);
83+
case FROM_XYZ -> cs.fromCIEXYZ(new float[3]);
84+
}
85+
} catch (Throwable t) {
86+
t.printStackTrace();
87+
failed = true;
88+
}
89+
});
90+
}
91+
for (Thread t : ts) {
92+
t.start();
93+
}
94+
for (Thread t : ts) {
95+
t.join();
96+
}
97+
}
98+
99+
private static boolean isComplete() {
100+
return endtime - System.nanoTime() < 0 || failed;
101+
}
102+
}

0 commit comments

Comments
 (0)