Skip to content

Commit 3619545

Browse files
authored
Merge pull request #639 from zakkak/2023-12-18-23.0-jan-cpu-backports
[23.0] Backport: Throw exception for null pointers passed to RuntimeJNIAccess / RuntimeReflection register methods
2 parents a55af47 + da31858 commit 3619545

File tree

5 files changed

+153
-2
lines changed

5 files changed

+153
-2
lines changed

substratevm/mx.substratevm/mx_substratevm.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#
22
# ----------------------------------------------------------------------------------------------------
33
#
4-
# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
4+
# Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
55
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
66
#
77
# This code is free software; you can redistribute it and/or modify it
@@ -305,7 +305,7 @@ def native_image_func(args, **kwargs):
305305
yield native_image_func
306306

307307
native_image_context.hosted_assertions = ['-J-ea', '-J-esa']
308-
_native_unittest_features = '--features=com.oracle.svm.test.ImageInfoTest$TestFeature,com.oracle.svm.test.ServiceLoaderTest$TestFeature,com.oracle.svm.test.SecurityServiceTest$TestFeature'
308+
_native_unittest_features = '--features=com.oracle.svm.test.ImageInfoTest$TestFeature,com.oracle.svm.test.ServiceLoaderTest$TestFeature,com.oracle.svm.test.SecurityServiceTest$TestFeature,com.oracle.svm.test.ReflectionRegistrationTest$TestFeature'
309309

310310
IMAGE_ASSERTION_FLAGS = ['-H:+VerifyGraalGraphs', '-H:+VerifyPhases']
311311

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ConditionalConfigurationRegistry.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import java.util.Collection;
2828
import java.util.Map;
29+
import java.util.Objects;
2930
import java.util.concurrent.ConcurrentHashMap;
3031
import java.util.concurrent.ConcurrentLinkedQueue;
3132

@@ -38,6 +39,8 @@ public abstract class ConditionalConfigurationRegistry {
3839
private final Map<String, Collection<Runnable>> pendingReachabilityHandlers = new ConcurrentHashMap<>();
3940

4041
protected void registerConditionalConfiguration(ConfigurationCondition condition, Runnable runnable) {
42+
Objects.requireNonNull(condition, "Cannot use null value as condition for conditional configuration. Please ensure that you register a non-null condition.");
43+
Objects.requireNonNull(runnable, "Cannot use null value as runnable for conditional configuration. Please ensure that you register a non-null runnable.");
4144
if (ConfigurationCondition.alwaysTrue().equals(condition)) {
4245
/* analysis optimization to include new types as early as possible */
4346
runnable.run();

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.util.IdentityHashMap;
3535
import java.util.List;
3636
import java.util.Map;
37+
import java.util.Objects;
3738
import java.util.Set;
3839
import java.util.concurrent.ConcurrentHashMap;
3940
import java.util.function.Predicate;
@@ -202,18 +203,21 @@ private class JNIRuntimeAccessibilitySupportImpl extends ConditionalConfiguratio
202203
@Override
203204
public void register(ConfigurationCondition condition, boolean unsafeAllocated, Class<?> clazz) {
204205
assert !unsafeAllocated : "unsafeAllocated can be only set via Unsafe.allocateInstance, not via JNI.";
206+
Objects.requireNonNull(clazz, () -> nullErrorMessage("class"));
205207
abortIfSealed();
206208
registerConditionalConfiguration(condition, () -> newClasses.add(clazz));
207209
}
208210

209211
@Override
210212
public void register(ConfigurationCondition condition, boolean queriedOnly, Executable... methods) {
213+
requireNonNull(methods, "methods");
211214
abortIfSealed();
212215
registerConditionalConfiguration(condition, () -> newMethods.addAll(Arrays.asList(methods)));
213216
}
214217

215218
@Override
216219
public void register(ConfigurationCondition condition, boolean finalIsWritable, Field... fields) {
220+
requireNonNull(fields, "field");
217221
abortIfSealed();
218222
registerConditionalConfiguration(condition, () -> registerFields(finalIsWritable, fields));
219223
}
@@ -622,4 +626,14 @@ private static boolean anyFieldMatches(ResolvedJavaType sub, String name) {
622626
return false;
623627
}
624628
}
629+
630+
private static void requireNonNull(Object[] values, String kind) {
631+
for (Object value : values) {
632+
Objects.requireNonNull(value, () -> nullErrorMessage(kind));
633+
}
634+
}
635+
636+
private static String nullErrorMessage(String kind) {
637+
return "Cannot register null value as " + kind + " for JNI access. Please ensure that all values you register are not null.";
638+
}
625639
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import java.util.Collections;
5757
import java.util.List;
5858
import java.util.Map;
59+
import java.util.Objects;
5960
import java.util.Optional;
6061
import java.util.Set;
6162
import java.util.concurrent.Callable;
@@ -166,6 +167,7 @@ private void setQueryFlag(Class<?> clazz, int flag) {
166167

167168
@Override
168169
public void register(ConfigurationCondition condition, boolean unsafeInstantiated, Class<?> clazz) {
170+
Objects.requireNonNull(clazz, () -> nullErrorMessage("class"));
169171
checkNotSealed();
170172
register(analysisUniverse -> registerConditionalConfiguration(condition,
171173
() -> analysisUniverse.getBigbang().postTask(debug -> registerClass(clazz, unsafeInstantiated))));
@@ -269,6 +271,7 @@ public void registerAllSignersQuery(ConfigurationCondition condition, Class<?> c
269271

270272
@Override
271273
public void register(ConfigurationCondition condition, boolean queriedOnly, Executable... executables) {
274+
requireNonNull(executables, "executable");
272275
checkNotSealed();
273276
register(analysisUniverse -> registerConditionalConfiguration(condition, () -> {
274277
for (Executable executable : executables) {
@@ -397,6 +400,7 @@ public void registerConstructorLookup(ConfigurationCondition condition, Class<?>
397400

398401
@Override
399402
public void register(ConfigurationCondition condition, boolean finalIsWritable, Field... fields) {
403+
requireNonNull(fields, "field");
400404
checkNotSealed();
401405
registerInternal(condition, fields);
402406
}
@@ -1061,4 +1065,14 @@ public int getReflectionMethodsCount() {
10611065
public int getReflectionFieldsCount() {
10621066
return registeredFields.size();
10631067
}
1068+
1069+
private static void requireNonNull(Object[] values, String kind) {
1070+
for (Object value : values) {
1071+
Objects.requireNonNull(value, () -> nullErrorMessage(kind));
1072+
}
1073+
}
1074+
1075+
private static String nullErrorMessage(String kind) {
1076+
return "Cannot register null value as " + kind + " for reflection. Please ensure that all values you register are not null.";
1077+
}
10641078
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2023, 2023, Red Hat Inc. All rights reserved.
4+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+
*
6+
* This code is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License version 2 only, as
8+
* published by the Free Software Foundation. Oracle designates this
9+
* particular file as subject to the "Classpath" exception as provided
10+
* by Oracle in the LICENSE file that accompanied this code.
11+
*
12+
* This code is distributed in the hope that it will be useful, but WITHOUT
13+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15+
* version 2 for more details (a copy is included in the LICENSE file that
16+
* accompanied this code).
17+
*
18+
* You should have received a copy of the GNU General Public License version
19+
* 2 along with this work; if not, write to the Free Software Foundation,
20+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21+
*
22+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23+
* or visit www.oracle.com if you need additional information or have any
24+
* questions.
25+
*/
26+
package com.oracle.svm.test;
27+
28+
import com.oracle.svm.hosted.FeatureImpl;
29+
import com.oracle.svm.hosted.substitute.SubstitutionReflectivityFilter;
30+
import org.graalvm.nativeimage.ImageSingletons;
31+
import org.graalvm.nativeimage.hosted.Feature;
32+
import org.graalvm.nativeimage.hosted.RuntimeReflection;
33+
import org.graalvm.nativeimage.impl.RuntimeReflectionSupport;
34+
import org.junit.Test;
35+
36+
import java.lang.reflect.Executable;
37+
import java.lang.reflect.Field;
38+
39+
/**
40+
* Tests the {@link RuntimeReflection}.
41+
*/
42+
public class ReflectionRegistrationTest {
43+
44+
public static class TestFeature implements Feature {
45+
46+
@SuppressWarnings("unused")//
47+
int unusedVariableOne = 1;
48+
@SuppressWarnings("unused")//
49+
int unusedVariableTwo = 2;
50+
51+
@Override
52+
public void beforeAnalysis(final BeforeAnalysisAccess access) {
53+
try {
54+
RuntimeReflection.register((Class<?>) null);
55+
assert false;
56+
} catch (NullPointerException e) {
57+
assert e.getMessage().startsWith("Cannot register null value");
58+
}
59+
try {
60+
RuntimeReflection.register((Executable) null);
61+
assert false;
62+
} catch (NullPointerException e) {
63+
assert e.getMessage().startsWith("Cannot register null value");
64+
}
65+
try {
66+
RuntimeReflection.register((Field) null);
67+
assert false;
68+
} catch (NullPointerException e) {
69+
assert e.getMessage().startsWith("Cannot register null value");
70+
}
71+
72+
try {
73+
ImageSingletons.lookup(RuntimeReflectionSupport.class).register(null, this.getClass());
74+
assert false;
75+
} catch (NullPointerException e) {
76+
assert e.getMessage().startsWith("Cannot use null value");
77+
}
78+
79+
try {
80+
ImageSingletons.lookup(RuntimeReflectionSupport.class).register(null, true, this.getClass().getMethods());
81+
assert false;
82+
} catch (NullPointerException e) {
83+
assert e.getMessage().startsWith("Cannot use null value");
84+
}
85+
86+
try {
87+
ImageSingletons.lookup(RuntimeReflectionSupport.class).register(null, true, this.getClass().getFields());
88+
assert false;
89+
} catch (NullPointerException e) {
90+
assert e.getMessage().startsWith("Cannot use null value");
91+
}
92+
93+
FeatureImpl.BeforeAnalysisAccessImpl impl = (FeatureImpl.BeforeAnalysisAccessImpl) access;
94+
try {
95+
SubstitutionReflectivityFilter.shouldExclude((Class<?>) null, impl.getMetaAccess(), impl.getUniverse());
96+
assert false;
97+
} catch (NullPointerException e) {
98+
// expected
99+
}
100+
try {
101+
SubstitutionReflectivityFilter.shouldExclude((Executable) null, impl.getMetaAccess(), impl.getUniverse());
102+
assert false;
103+
} catch (NullPointerException e) {
104+
// expected
105+
}
106+
try {
107+
SubstitutionReflectivityFilter.shouldExclude((Field) null, impl.getMetaAccess(), impl.getUniverse());
108+
assert false;
109+
} catch (NullPointerException e) {
110+
// expected
111+
}
112+
}
113+
114+
}
115+
116+
@Test
117+
public void test() {
118+
// nothing to do
119+
}
120+
}

0 commit comments

Comments
 (0)