Skip to content

Commit 55354dd

Browse files
committed
8264666: Change implementation of safeAdd/safeMult in the LCMSImageLayout class
Reviewed-by: phh Backport-of: 3ef9ce6
1 parent 1549bb1 commit 55354dd

File tree

2 files changed

+180
-26
lines changed

2 files changed

+180
-26
lines changed

src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -335,44 +335,30 @@ public static BandOrder getBandOrder(int[] bandOffsets) {
335335
}
336336

337337
private void verify() throws ImageLayoutException {
338-
339-
if (offset < 0 || offset >= dataArrayLength) {
340-
throw new ImageLayoutException("Invalid image layout");
341-
}
342-
338+
checkIndex(offset, dataArrayLength);
343339
if (nextPixelOffset != getBytesPerPixel(pixelType)) {
344340
throw new ImageLayoutException("Invalid image layout");
345341
}
346342

347343
int lastScanOffset = safeMult(nextRowOffset, (height - 1));
348-
349344
int lastPixelOffset = safeMult(nextPixelOffset, (width -1 ));
345+
long off = (long) offset + lastPixelOffset + lastScanOffset;
350346

351-
lastPixelOffset = safeAdd(lastPixelOffset, lastScanOffset);
352-
353-
int off = safeAdd(offset, lastPixelOffset);
354-
355-
if (off < 0 || off >= dataArrayLength) {
356-
throw new ImageLayoutException("Invalid image layout");
357-
}
347+
checkIndex(off, dataArrayLength);
358348
}
359349

360-
static int safeAdd(int a, int b) throws ImageLayoutException {
361-
long res = a;
362-
res += b;
363-
if (res < Integer.MIN_VALUE || res > Integer.MAX_VALUE) {
350+
private static int checkIndex(long index, int length)
351+
throws ImageLayoutException
352+
{
353+
if (index < 0 || index >= length) {
364354
throw new ImageLayoutException("Invalid image layout");
365355
}
366-
return (int)res;
356+
return (int) index;
367357
}
368358

369-
static int safeMult(int a, int b) throws ImageLayoutException {
370-
long res = a;
371-
res *= b;
372-
if (res < Integer.MIN_VALUE || res > Integer.MAX_VALUE) {
373-
throw new ImageLayoutException("Invalid image layout");
374-
}
375-
return (int)res;
359+
private static int safeMult(int a, int b) throws ImageLayoutException {
360+
long res = (long) a * b;
361+
return checkIndex(res, Integer.MAX_VALUE);
376362
}
377363

378364
@SuppressWarnings("serial") // JDK-implementation class
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/*
2+
* Copyright Amazon.com Inc. 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.image.BufferedImage;
26+
import java.awt.image.ColorConvertOp;
27+
import java.util.concurrent.atomic.AtomicInteger;
28+
29+
import static java.awt.image.BufferedImage.TYPE_3BYTE_BGR;
30+
import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR;
31+
import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR_PRE;
32+
import static java.awt.image.BufferedImage.TYPE_BYTE_BINARY;
33+
import static java.awt.image.BufferedImage.TYPE_BYTE_GRAY;
34+
import static java.awt.image.BufferedImage.TYPE_BYTE_INDEXED;
35+
import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
36+
import static java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE;
37+
import static java.awt.image.BufferedImage.TYPE_INT_BGR;
38+
import static java.awt.image.BufferedImage.TYPE_INT_RGB;
39+
import static java.awt.image.BufferedImage.TYPE_USHORT_555_RGB;
40+
import static java.awt.image.BufferedImage.TYPE_USHORT_565_RGB;
41+
import static java.awt.image.BufferedImage.TYPE_USHORT_GRAY;
42+
43+
/**
44+
* @test
45+
* @bug 8264666
46+
* @summary No exception or errors should occur in ColorConvertOp.filter().
47+
*/
48+
public final class UnexpectedSourceImageSize {
49+
50+
private static final int SIZE = 100;
51+
52+
private static final int[] TYPES = {
53+
TYPE_INT_RGB, TYPE_INT_ARGB, TYPE_INT_ARGB_PRE, TYPE_INT_BGR,
54+
TYPE_3BYTE_BGR, TYPE_4BYTE_ABGR, TYPE_4BYTE_ABGR_PRE,
55+
TYPE_USHORT_565_RGB, TYPE_USHORT_555_RGB, TYPE_BYTE_GRAY,
56+
TYPE_USHORT_GRAY, TYPE_BYTE_BINARY, TYPE_BYTE_INDEXED
57+
};
58+
private static final int[] INTERESTING_POINTS = new int[]{
59+
Integer.MIN_VALUE / SIZE - 1,
60+
-SIZE, -3, -1, 0, 1, 3,
61+
Integer.MAX_VALUE / SIZE + 1,
62+
};
63+
private static final int[] CSs = new int[]{
64+
ColorSpace.CS_sRGB, ColorSpace.CS_LINEAR_RGB, ColorSpace.CS_CIEXYZ,
65+
ColorSpace.CS_PYCC, ColorSpace.CS_GRAY
66+
};
67+
68+
public static void main(String[] args) throws Exception {
69+
Thread[] threads = new Thread[CSs.length];
70+
for (int i = 0; i < threads.length; i++) {
71+
ColorSpace cs = ColorSpace.getInstance(CSs[i]);
72+
threads[i] = new Thread(() -> {
73+
for (final int type : TYPES) {
74+
test(cs, type);
75+
}
76+
});
77+
threads[i].start();
78+
}
79+
for (int i = 0; i < CSs.length; i++) {
80+
threads[i].join();
81+
}
82+
}
83+
84+
/**
85+
* 1. Checks how many times the width/height are requested during filter()
86+
* 2. Repeats step1, but returns some random data for each request
87+
*/
88+
private static void test(ColorSpace cs, int type) {
89+
AtomicInteger srcCountW = new AtomicInteger();
90+
AtomicInteger srcCountH = new AtomicInteger();
91+
AtomicInteger dstCountW = new AtomicInteger();
92+
AtomicInteger dstCountH = new AtomicInteger();
93+
94+
BufferedImage dstBI = new BufferedImage(SIZE, SIZE, type) {
95+
public int getWidth() {
96+
dstCountW.incrementAndGet();
97+
return super.getWidth();
98+
}
99+
public int getHeight() {
100+
dstCountH.incrementAndGet();
101+
return super.getHeight();
102+
}
103+
};
104+
BufferedImage srcBI = new BufferedImage(SIZE, SIZE, type) {
105+
public int getWidth() {
106+
srcCountW.incrementAndGet();
107+
return super.getWidth();
108+
}
109+
public int getHeight() {
110+
srcCountH.incrementAndGet();
111+
return super.getHeight();
112+
}
113+
};
114+
115+
filter(srcBI, cs, dstBI);
116+
if (dstCountW.get() == 0 && dstCountH.get() == 0
117+
&& srcCountW.get() == 0 && srcCountH.get() == 0) {
118+
// getWidth/getHeight are never called
119+
return;
120+
}
121+
for (int brokenH : INTERESTING_POINTS) {
122+
for (int brokenW : INTERESTING_POINTS) {
123+
for (int srcW = 0; srcW <= srcCountW.get(); ++srcW) {
124+
for (int srcH = 0; srcH <= srcCountH.get(); ++srcH) {
125+
srcBI = makeBI(type, brokenH, brokenW, srcW, srcH);
126+
for (int dstW = 0; dstW <= dstCountW.get(); ++dstW) {
127+
for (int dstH = 0; dstH <= dstCountH.get(); ++dstH) {
128+
try {
129+
dstBI = makeBI(type, brokenH, brokenW, dstW, dstH);
130+
filter(srcBI, cs, dstBI);
131+
} catch (Exception | OutOfMemoryError ignore) {
132+
}
133+
}
134+
}
135+
}
136+
}
137+
}
138+
}
139+
}
140+
141+
private static BufferedImage makeBI(int biType, int brokenH, int brokenW,
142+
int breakStepW, int breakStepH) {
143+
return new BufferedImage(SIZE, SIZE, biType) {
144+
private int stepW = 0;
145+
private int stepH = 0;
146+
public int getWidth() {
147+
if (stepW == breakStepW) {
148+
return brokenW;
149+
}
150+
stepW++;
151+
return super.getWidth();
152+
}
153+
public int getHeight() {
154+
if (stepH == breakStepH) {
155+
return brokenH;
156+
}
157+
stepH++;
158+
return super.getHeight();
159+
}
160+
};
161+
}
162+
163+
private static void filter(BufferedImage src, ColorSpace to,
164+
BufferedImage dest) {
165+
ColorConvertOp op = new ColorConvertOp(to, null);
166+
op.filter(src, dest);
167+
}
168+
}

0 commit comments

Comments
 (0)