Skip to content

Commit cd2866f

Browse files
committed
Validate reachable object before propagating it.
1 parent 46e36ff commit cd2866f

File tree

6 files changed

+42
-13
lines changed

6 files changed

+42
-13
lines changed

sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/Feature.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,9 @@ interface DuringSetupAccess extends FeatureAccess {
194194

195195
/**
196196
* Register a callback that is executed when an object of type {@code clazz}, or any of its
197-
* subtypes, is marked as reachable during heap scanning. The callback may be executed for
198-
* the same object by multiple worker threads concurrently.
197+
* subtypes, is marked as reachable during heap scanning. The callback is executed before
198+
* the object is added to the shadow heap. The callback may be executed for the same object
199+
* by multiple worker threads concurrently.
199200
*
200201
* @since 24.2
201202
*/

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java

+8
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,14 @@ public void notifyClassReachabilityListener(AnalysisUniverse universe, DuringAna
130130
}
131131
}
132132

133+
/**
134+
* Run validation checks for reachable objects before registering them in the shadow heap.
135+
*
136+
* @param obj the object to validate
137+
*/
138+
public void validateReachableObject(Object obj) {
139+
}
140+
133141
/**
134142
* Register newly created type.
135143
*

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java

+19-7
Original file line numberDiff line numberDiff line change
@@ -587,15 +587,25 @@ private ImageHeapConstant markReachable(ImageHeapConstant imageHeapConstant, Sca
587587
}
588588

589589
protected void onObjectReachable(ImageHeapConstant imageHeapConstant, ScanReason reason, Consumer<ScanReason> onAnalysisModified) {
590-
AnalysisType objectType = metaAccess.lookupJavaType(imageHeapConstant);
591-
imageHeap.addReachableObject(objectType, imageHeapConstant);
592590

593-
AnalysisType type = imageHeapConstant.getType();
594-
Object object = bb.getSnippetReflectionProvider().asObject(Object.class, imageHeapConstant);
595-
/* Simulated constants don't have a backing object and don't need to be processed. */
596-
if (object != null) {
591+
AnalysisType objectType = imageHeapConstant.getType();
592+
if (imageHeapConstant.isBackedByHostedObject()) {
593+
/* Simulated constants don't have a backing object and don't need to be processed. */
597594
try {
598-
type.notifyObjectReachable(universe.getConcurrentAnalysisAccess(), object, reason);
595+
Object object = bb.getSnippetReflectionProvider().asObject(Object.class, imageHeapConstant);
596+
/*
597+
* Before adding the object to ImageHeap.reachableObjects, where it could be read by
598+
* other threads, run validation checks, e.g., verify that the object's type can be
599+
* initialized at build time. Also run the validation before exposing the object to
600+
* other reachability hooks to avoid propagating an invalid object.
601+
*/
602+
hostVM.validateReachableObject(object);
603+
/*
604+
* Note that reachability hooks can also reject objects based on specific validation
605+
* conditions, e.g., a started Thread should never be added to the image heap, but
606+
* the structure of the object is valid, as ensured by the validity check above.
607+
*/
608+
objectType.notifyObjectReachable(universe.getConcurrentAnalysisAccess(), object, reason);
599609
} catch (UnsupportedFeatureException e) {
600610
/* Enhance the unsupported feature message with the object trace and rethrow. */
601611
StringBuilder backtrace = new StringBuilder();
@@ -604,6 +614,8 @@ protected void onObjectReachable(ImageHeapConstant imageHeapConstant, ScanReason
604614
}
605615
}
606616

617+
imageHeap.addReachableObject(objectType, imageHeapConstant);
618+
607619
markTypeInstantiated(objectType, reason);
608620
if (imageHeapConstant instanceof ImageHeapObjectArray imageHeapArray) {
609621
AnalysisType arrayType = imageHeapArray.getType();

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555

5656
import com.oracle.graal.pointsto.BigBang;
5757
import com.oracle.graal.pointsto.ObjectScanner;
58+
import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException;
5859
import com.oracle.graal.pointsto.heap.ImageHeapConstant;
5960
import com.oracle.graal.pointsto.heap.ImageHeapScanner;
6061
import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor;
@@ -309,7 +310,10 @@ public void registerObjectToConstantReplacer(Function<Object, ImageHeapConstant>
309310

310311
/**
311312
* Register a callback that is executed when an object of the specified type or any of its
312-
* subtypes is marked as reachable.
313+
* subtypes is marked as reachable. The callback is executed before the object is added to
314+
* the shadow heap. A callback may throw an {@link UnsupportedFeatureException} to reject an
315+
* object based on specific validation rules. This will stop the image build and report how
316+
* the object was reached.
313317
*
314318
* @since 24.0
315319
*/

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

+6
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import java.util.function.BiPredicate;
4646
import java.util.function.Function;
4747

48+
import com.oracle.svm.hosted.classinitialization.ClassInitializationFeature;
4849
import org.graalvm.nativeimage.AnnotationAccess;
4950
import org.graalvm.nativeimage.ImageSingletons;
5051
import org.graalvm.nativeimage.Platform;
@@ -360,6 +361,11 @@ public boolean isRelocatedPointer(JavaConstant constant) {
360361
return constant instanceof RelocatableConstant;
361362
}
362363

364+
@Override
365+
public void validateReachableObject(Object obj) {
366+
ImageSingletons.lookup(ClassInitializationFeature.class).checkImageHeapInstance(obj);
367+
}
368+
363369
@Override
364370
public void registerType(AnalysisType analysisType) {
365371
DynamicHub hub = createHub(analysisType);

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838

3939
import org.graalvm.nativeimage.impl.clinit.ClassInitializationTracking;
4040

41-
import com.oracle.graal.pointsto.ObjectScanner;
4241
import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException;
4342
import com.oracle.graal.pointsto.meta.AnalysisMethod;
4443
import com.oracle.graal.pointsto.meta.AnalysisType;
@@ -142,11 +141,10 @@ private static void initializeNativeImagePackagesAtBuildTime(ClassInitialization
142141
public void duringSetup(DuringSetupAccess a) {
143142
FeatureImpl.DuringSetupAccessImpl access = (FeatureImpl.DuringSetupAccessImpl) a;
144143
classInitializationSupport = access.getHostVM().getClassInitializationSupport();
145-
access.registerObjectReachableCallback(Object.class, this::checkImageHeapInstance);
146144
}
147145

148146
@SuppressWarnings("unused")
149-
private void checkImageHeapInstance(DuringAnalysisAccess access, Object obj, ObjectScanner.ScanReason reason) {
147+
public void checkImageHeapInstance(Object obj) {
150148
/*
151149
* Note that initializeAtBuildTime also memoizes the class as InitKind.BUILD_TIME, which
152150
* means that the user cannot later manually register it as RERUN or RUN_TIME.

0 commit comments

Comments
 (0)