Skip to content

Commit 1bfa68b

Browse files
author
Christian Wimmer
committed
Add verification for invoke receiver types
1 parent ab3a2ae commit 1bfa68b

File tree

4 files changed

+76
-3
lines changed

4 files changed

+76
-3
lines changed

compiler/src/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ private final class AddInputsFilter extends Node.EdgeVisitor {
517517
@Override
518518
public Node apply(Node self, Node input) {
519519
if (!input.isAlive()) {
520-
assert !input.isDeleted();
520+
assert !input.isDeleted() : input;
521521
return addOrUniqueWithInputs(input);
522522
} else {
523523
return input;

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,4 +620,7 @@ protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, String ol
620620
@APIOption(name = "configure-reflection-metadata")//
621621
@Option(help = "Limit method reflection metadata to configuration entries instead of including it for all reachable methods")//
622622
public static final HostedOptionKey<Boolean> ConfigureReflectionMetadata = new HostedOptionKey<>(true);
623+
624+
@Option(help = "Verify type states computed by the static analysis at run time", type = Debug)//
625+
public static final HostedOptionKey<Boolean> VerifyTypes = new HostedOptionKey<>(true);
623626
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,19 @@
3333
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
3434
import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
3535
import org.graalvm.compiler.core.common.type.StampPair;
36+
import org.graalvm.compiler.core.common.type.TypeReference;
3637
import org.graalvm.compiler.debug.DebugHandlersFactory;
3738
import org.graalvm.compiler.graph.Node;
3839
import org.graalvm.compiler.graph.NodeInputList;
40+
import org.graalvm.compiler.nodes.BeginNode;
3941
import org.graalvm.compiler.nodes.CallTargetNode;
4042
import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
4143
import org.graalvm.compiler.nodes.ConstantNode;
4244
import org.graalvm.compiler.nodes.DirectCallTargetNode;
4345
import org.graalvm.compiler.nodes.FixedGuardNode;
4446
import org.graalvm.compiler.nodes.FixedNode;
47+
import org.graalvm.compiler.nodes.FixedWithNextNode;
48+
import org.graalvm.compiler.nodes.IfNode;
4549
import org.graalvm.compiler.nodes.IndirectCallTargetNode;
4650
import org.graalvm.compiler.nodes.Invoke;
4751
import org.graalvm.compiler.nodes.InvokeNode;
@@ -54,11 +58,15 @@
5458
import org.graalvm.compiler.nodes.StructuredGraph;
5559
import org.graalvm.compiler.nodes.ValueNode;
5660
import org.graalvm.compiler.nodes.calc.IsNullNode;
61+
import org.graalvm.compiler.nodes.extended.BranchProbabilityNode;
5762
import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode;
5863
import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind;
64+
import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode;
5965
import org.graalvm.compiler.nodes.extended.ForeignCallNode;
6066
import org.graalvm.compiler.nodes.extended.GetClassNode;
6167
import org.graalvm.compiler.nodes.extended.LoadHubNode;
68+
import org.graalvm.compiler.nodes.extended.OpaqueNode;
69+
import org.graalvm.compiler.nodes.java.InstanceOfNode;
6270
import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
6371
import org.graalvm.compiler.nodes.memory.OnHeapMemoryAccess.BarrierType;
6472
import org.graalvm.compiler.nodes.memory.ReadNode;
@@ -73,6 +81,8 @@
7381
import org.graalvm.word.LocationIdentity;
7482

7583
import com.oracle.svm.core.FrameAccess;
84+
import com.oracle.svm.core.SubstrateOptions;
85+
import com.oracle.svm.core.SubstrateUtil;
7686
import com.oracle.svm.core.code.CodeInfoTable;
7787
import com.oracle.svm.core.graal.code.SubstrateBackend;
7888
import com.oracle.svm.core.graal.meta.RuntimeConfiguration;
@@ -81,6 +91,8 @@
8191
import com.oracle.svm.core.meta.SharedMethod;
8292
import com.oracle.svm.core.meta.SubstrateObjectConstant;
8393
import com.oracle.svm.core.snippets.ImplicitExceptions;
94+
import com.oracle.svm.core.snippets.SnippetRuntime;
95+
import com.oracle.svm.core.snippets.SubstrateForeignCallTarget;
8496
import com.oracle.svm.core.util.VMError;
8597

8698
import jdk.vm.ci.code.CallingConvention;
@@ -93,9 +105,14 @@
93105

94106
public abstract class NonSnippetLowerings {
95107

108+
public static final SnippetRuntime.SubstrateForeignCallDescriptor REPORT_VERIFY_TYPES_ERROR = SnippetRuntime.findForeignCall(
109+
NonSnippetLowerings.class, "reportVerifyTypesError", false, LocationIdentity.any());
110+
96111
private final RuntimeConfiguration runtimeConfig;
97112
private final Predicate<ResolvedJavaMethod> mustNotAllocatePredicate;
98113

114+
final boolean verifyTypes = SubstrateOptions.VerifyTypes.getValue();
115+
99116
@SuppressWarnings("unused")
100117
protected NonSnippetLowerings(RuntimeConfiguration runtimeConfig, Predicate<ResolvedJavaMethod> mustNotAllocatePredicate, OptionValues options, Iterable<DebugHandlersFactory> factories,
101118
Providers providers, SnippetReflectionProvider snippetReflection, Map<Class<? extends Node>, NodeLoweringProvider<?>> lowerings) {
@@ -250,12 +267,53 @@ public void lower(FixedNode node, LoweringTool tool) {
250267
SharedMethod method = (SharedMethod) callTarget.targetMethod();
251268
JavaType[] signature = method.getSignature().toParameterTypes(callTarget.isStatic() ? null : method.getDeclaringClass());
252269
CallingConvention.Type callType = method.getCallingConventionKind().toType(true);
253-
254270
InvokeKind invokeKind = callTarget.invokeKind();
255271
SharedMethod[] implementations = method.getImplementations();
272+
273+
if (verifyTypes && !callTarget.isStatic() && receiver.getStackKind() == JavaKind.Object && !((SharedMethod) graph.method()).isUninterruptible()) {
274+
/*
275+
* Verify that the receiver is an instance of the class that declares the call
276+
* target method. To avoid that the new type check floats above a deoptimization
277+
* entry point, we need to anchor the receiver to the control flow. To avoid
278+
* that Graal optimizes away the InstanceOfNode immediately, we need an
279+
* OpaqueNode that removes all type information from the receiver. Then we wire
280+
* up an IfNode that leads to a ForeignCallNode in case the verification fails.
281+
*/
282+
FixedValueAnchorNode anchoredReceiver = graph.add(new FixedValueAnchorNode(receiver));
283+
graph.addBeforeFixed(node, anchoredReceiver);
284+
ValueNode opaqueReceiver = graph.unique(new OpaqueNode(anchoredReceiver));
285+
TypeReference declaringClass = TypeReference.createTrustedWithoutAssumptions(method.getDeclaringClass());
286+
LogicNode instanceOf = graph.addOrUniqueWithInputs(InstanceOfNode.create(declaringClass, opaqueReceiver));
287+
BeginNode passingBegin = graph.add(new BeginNode());
288+
BeginNode failingBegin = graph.add(new BeginNode());
289+
IfNode ifNode = graph.add(new IfNode(instanceOf, passingBegin, failingBegin, BranchProbabilityNode.EXTREMELY_FAST_PATH_PROFILE));
290+
291+
((FixedWithNextNode) node.predecessor()).setNext(ifNode);
292+
passingBegin.setNext(node);
293+
294+
String errorMessage;
295+
if (SubstrateUtil.HOSTED) {
296+
errorMessage = "Invoke " + invokeKind + " of " + method.format("%H.%n(%p)%r");
297+
errorMessage += System.lineSeparator() + " declaringClass = " + declaringClass;
298+
if (implementations.length == 0 || implementations.length > 10) {
299+
errorMessage += System.lineSeparator() + " implementations.length = " + implementations.length;
300+
} else {
301+
for (int i = 0; i < implementations.length; i++) {
302+
errorMessage += System.lineSeparator() + " implementations[" + i + "] = " + implementations[i].format("%H.%n(%p)%r");
303+
}
304+
}
305+
} else {
306+
errorMessage = "Invoke (method name not added because message must be a compile-time constant)";
307+
}
308+
ConstantNode errorConstant = ConstantNode.forConstant(tool.getConstantReflection().forString(errorMessage), tool.getMetaAccess(), graph);
309+
ForeignCallNode reportError = graph.add(new ForeignCallNode(REPORT_VERIFY_TYPES_ERROR, opaqueReceiver, errorConstant));
310+
reportError.setStateAfter(invoke.stateAfter().duplicateModifiedDuringCall(invoke.bci(), node.getStackKind()));
311+
failingBegin.setNext(reportError);
312+
reportError.setNext(graph.add(new LoweredDeadEndNode()));
313+
}
314+
256315
LoadHubNode hub = null;
257316
CallTargetNode loweredCallTarget;
258-
259317
if (invokeKind.isDirect() || implementations.length == 1) {
260318
SharedMethod targetMethod = method;
261319
if (!invokeKind.isDirect()) {
@@ -352,4 +410,8 @@ private CallTargetNode createUnreachableCallTarget(LoweringTool tool, FixedNode
352410
}
353411
}
354412

413+
@SubstrateForeignCallTarget(stubCallingConvention = true)
414+
private static void reportVerifyTypesError(Object object, String message) {
415+
throw VMError.shouldNotReachHere("VerifyTypes found a type error for object " + (object == null ? "null" : object.getClass().getTypeName()) + ": " + message);
416+
}
355417
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ImplicitExceptionsFeature.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@
2525
package com.oracle.svm.hosted.snippets;
2626

2727
import com.oracle.graal.pointsto.meta.AnalysisMethod;
28+
import com.oracle.svm.core.SubstrateOptions;
2829
import com.oracle.svm.core.annotate.AutomaticFeature;
2930
import com.oracle.svm.core.graal.GraalFeature;
3031
import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider;
32+
import com.oracle.svm.core.graal.snippets.NonSnippetLowerings;
3133
import com.oracle.svm.core.snippets.ExceptionUnwind;
3234
import com.oracle.svm.core.snippets.ImplicitExceptions;
3335
import com.oracle.svm.core.snippets.SnippetRuntime.SubstrateForeignCallDescriptor;
@@ -46,11 +48,17 @@ public void beforeAnalysis(BeforeAnalysisAccess a) {
4648
for (SubstrateForeignCallDescriptor descriptor : ExceptionUnwind.FOREIGN_CALLS) {
4749
access.getBigBang().addRootMethod((AnalysisMethod) descriptor.findMethod(access.getMetaAccess()));
4850
}
51+
if (SubstrateOptions.VerifyTypes.getValue()) {
52+
access.getBigBang().addRootMethod((AnalysisMethod) NonSnippetLowerings.REPORT_VERIFY_TYPES_ERROR.findMethod(access.getMetaAccess()));
53+
}
4954
}
5055

5156
@Override
5257
public void registerForeignCalls(SubstrateForeignCallsProvider foreignCalls) {
5358
foreignCalls.register(ImplicitExceptions.FOREIGN_CALLS);
5459
foreignCalls.register(ExceptionUnwind.FOREIGN_CALLS);
60+
if (SubstrateOptions.VerifyTypes.getValue()) {
61+
foreignCalls.register(NonSnippetLowerings.REPORT_VERIFY_TYPES_ERROR);
62+
}
5563
}
5664
}

0 commit comments

Comments
 (0)