8367384: The ICC_Profile class may throw exceptions during serialization

Reviewed-by: honkar, prr
This commit is contained in:
Sergey Bylokhov 2025-10-03 17:49:59 +00:00 committed by Harshitha Onkar
parent 0935b76c6b
commit 0e98ec3662
25 changed files with 191 additions and 32 deletions

View File

@ -41,6 +41,7 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
@ -1549,33 +1550,19 @@ public sealed class ICC_Profile implements Serializable
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
String csName = (String) s.readObject();
byte[] data = (byte[]) s.readObject();
int cspace = 0; // ColorSpace.CS_* constant if known
boolean isKnownPredefinedCS = false;
if (csName != null) {
isKnownPredefinedCS = true;
if (csName.equals("CS_sRGB")) {
cspace = ColorSpace.CS_sRGB;
} else if (csName.equals("CS_CIEXYZ")) {
cspace = ColorSpace.CS_CIEXYZ;
} else if (csName.equals("CS_PYCC")) {
cspace = ColorSpace.CS_PYCC;
} else if (csName.equals("CS_GRAY")) {
cspace = ColorSpace.CS_GRAY;
} else if (csName.equals("CS_LINEAR_RGB")) {
cspace = ColorSpace.CS_LINEAR_RGB;
} else {
isKnownPredefinedCS = false;
}
}
if (isKnownPredefinedCS) {
resolvedDeserializedProfile = getInstance(cspace);
} else {
resolvedDeserializedProfile = getInstance(data);
try {
String csName = (String) s.readObject();
byte[] data = (byte[]) s.readObject();
resolvedDeserializedProfile = switch (csName) {
case "CS_sRGB" -> getInstance(ColorSpace.CS_sRGB);
case "CS_CIEXYZ" -> getInstance(ColorSpace.CS_CIEXYZ);
case "CS_PYCC" -> getInstance(ColorSpace.CS_PYCC);
case "CS_GRAY" -> getInstance(ColorSpace.CS_GRAY);
case "CS_LINEAR_RGB" -> getInstance(ColorSpace.CS_LINEAR_RGB);
case null, default -> getInstance(data);
};
} catch (ClassCastException | IllegalArgumentException e) {
throw new InvalidObjectException("Invalid ICC Profile Data", e);
}
}

View File

@ -0,0 +1,99 @@
/*
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.OptionalDataException;
/**
* @test
* @bug 8367384
* @summary Verify ICC_Profile serialization per spec, all name/data cases
*/
public final class SerializationSpecTest {
public static void main(String[] args) throws Exception {
// Serialization form for ICC_Profile includes version, profile name,
// and profile data. If the name is invalid or does not match a standard
// profile, the data is used. An exception is thrown only if both the
// name and the data are invalid, or if one of them is missing or is of
// the wrong type.
// Naming conventions used in test file names:
// null : null reference
// valid : valid standard profile name or valid profile data (byte[])
// invalid : unrecognized name or data with incorrect ICC header
// wrongType: incorrect type, e.g., int[] instead of String or byte[]
// No name or data
test("empty", OptionalDataException.class);
// Cases where only the profile name is present (no profile data)
test("null", OptionalDataException.class);
test("valid", OptionalDataException.class);
test("invalid", OptionalDataException.class);
test("wrongType", InvalidObjectException.class);
// The test files are named as <name>_<data>.ser
test("null_null", InvalidObjectException.class);
test("null_valid", null); // valid data is enough if name is null
test("null_invalid", InvalidObjectException.class);
test("null_wrongType", InvalidObjectException.class);
test("invalid_null", InvalidObjectException.class);
test("invalid_valid", null); // valid data is enough if name is invalid
test("invalid_invalid", InvalidObjectException.class);
test("invalid_wrongType", InvalidObjectException.class);
test("wrongType_null", InvalidObjectException.class);
test("wrongType_valid", InvalidObjectException.class);
test("wrongType_invalid", InvalidObjectException.class);
test("wrongType_wrongType", InvalidObjectException.class);
test("valid_null", null); // the valid name is enough
test("valid_valid", null); // the valid name is enough
test("valid_invalid", null); // the valid name is enough
test("valid_wrongType", InvalidObjectException.class);
}
private static void test(String test, Class<?> expected) {
String fileName = test + ".ser";
File file = new File(System.getProperty("test.src", "."), fileName);
Class<?> actual = null;
try (var fis = new FileInputStream(file);
var ois = new ObjectInputStream(fis))
{
ois.readObject();
} catch (Exception e) {
actual = e.getClass();
}
if (actual != expected) {
System.err.println("Test: " + test);
System.err.println("Expected: " + expected);
System.err.println("Actual: " + actual);
throw new RuntimeException("Test failed");
}
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* @test
* @bug 8367384
* @summary Checks ICC_Profile serialization for standard profiles
*/
public final class StandardProfilesRoundTrip {
private static final ICC_Profile[] PROFILES = {
ICC_Profile.getInstance(ColorSpace.CS_sRGB),
ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB),
ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ),
ICC_Profile.getInstance(ColorSpace.CS_PYCC),
ICC_Profile.getInstance(ColorSpace.CS_GRAY)
};
public static void main(String[] args) throws Exception {
// Test profiles one by one
for (ICC_Profile profile : PROFILES) {
test(profile);
}
// Test all profiles at once
test(PROFILES);
}
private static void test(ICC_Profile... profiles) throws Exception {
byte[] data;
try (var bos = new ByteArrayOutputStream();
var oos = new ObjectOutputStream(bos))
{
for (ICC_Profile p : profiles) {
oos.writeObject(p);
}
data = bos.toByteArray();
}
try (var ois = new ObjectInputStream(new ByteArrayInputStream(data))) {
for (ICC_Profile p : profiles) {
if (p != ois.readObject()) {
throw new RuntimeException("Wrong deserialized object");
}
}
}
}
}

View File

@ -161,8 +161,8 @@ public class ValidateICCHeaderData {
testProfileCreation(false);
System.out.println("CASE 14: Passed \n");
System.out.println("CASE 15: Testing Deserialization of ICC_Profile ...");
testDeserialization();
System.out.println("CASE 15: Testing loading of ICC_Profile from file ...");
testLoading();
System.out.println("CASE 15: Passed \n");
System.out.println("Successfully completed testing all 15 cases. Test Passed !!");
@ -261,9 +261,9 @@ public class ValidateICCHeaderData {
}
}
private static void testDeserialization() throws IOException {
//invalidSRGB.icc is serialized on older version of JDK
//Upon deserialization, the invalid profile is expected to throw IAE
private static void testLoading() throws IOException {
// invalidSRGB.icc is a profile file that was produced by an older JDK
// When attempting to load it, the current JDK is expected to throw IAE
try {
ICC_Profile.getInstance("./invalidSRGB.icc");
throw new RuntimeException("Test Failed ! Expected IAE NOT thrown");