Skip to content

Commit e1bdb6e

Browse files
committed
[GR-67460] Change language permission feature to print only a single violation per privileged method.
PullRequest: graal/21440
2 parents e4577f1 + 28cac52 commit e1bdb6e

File tree

3 files changed

+59
-6
lines changed

3 files changed

+59
-6
lines changed

substratevm/src/com.oracle.svm.truffle.tck/src/META-INF/native-image/native-image.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ JavaArgs = --add-exports org.graalvm.nativeimage.base/com.oracle.svm.util=ALL-UN
2121
--add-exports jdk.internal.vm.ci/jdk.vm.ci.meta=ALL-UNNAMED
2222

2323
ProvidedHostedOptions = \
24+
TruffleTCKCollectMode= \
2425
TruffleTCKPermissionsReportFile= \
2526
TruffleTCKPermissionsExcludeFiles= \
2627
TruffleTCKPermissionsMaxStackTraceDepth= \

substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/PermissionsFeature.java

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,25 @@ public enum ActionKind {
129129
Throw
130130
}
131131

132+
/**
133+
* Specifies how privileged method violations are reported. See
134+
* {@link Options#TruffleTCKCollectMode}.
135+
*/
136+
public enum CollectMode {
137+
/**
138+
* Reports only one violation in total.
139+
*/
140+
Single,
141+
/**
142+
* Reports one call path per privileged method used.
143+
*/
144+
SinglePrivilegedMethodUsage,
145+
/**
146+
* Reports all call paths for all violations.
147+
*/
148+
All
149+
}
150+
132151
public static class Options {
133152
@Option(help = "Path to file where to store report of Truffle language privilege access.")//
134153
public static final HostedOptionKey<String> TruffleTCKPermissionsReportFile = new HostedOptionKey<>(null);
@@ -151,6 +170,15 @@ public static class Options {
151170
"Warn": Log a warning message to stderr.
152171
"Throw" (default): Throw an exception and abort the native-image build process.""", type = OptionType.Expert)//
153172
public static final HostedOptionKey<ActionKind> TruffleTCKUnusedAllowListEntriesAction = new HostedOptionKey<>(ActionKind.Throw);
173+
174+
@Option(help = """
175+
Specifies how privileged method violations are reported.
176+
Available options:
177+
- Single: Reports only one violation in total.
178+
- SinglePrivilegedMethodUsage: Reports one call path per privileged method used.
179+
- All: Reports all call paths for all violations.
180+
""", type = OptionType.Expert)//
181+
public static final HostedOptionKey<CollectMode> TruffleTCKCollectMode = new HostedOptionKey<>(CollectMode.SinglePrivilegedMethodUsage);
154182
}
155183

156184
/**
@@ -346,6 +374,7 @@ public void afterAnalysis(AfterAnalysisAccess access) {
346374
}
347375
FeatureImpl.AfterAnalysisAccessImpl accessImpl = (FeatureImpl.AfterAnalysisAccessImpl) access;
348376
DebugContext debugContext = accessImpl.getDebugContext();
377+
CollectMode collectMode = Options.TruffleTCKCollectMode.getValue();
349378
try (DebugContext.Scope s = debugContext.scope(ClassUtil.getUnqualifiedName(getClass()))) {
350379
BigBang bb = accessImpl.getBigBang();
351380
Map<BaseMethodNode, Set<BaseMethodNode>> cg = callGraph(bb, deniedMethods, debugContext, (SVMHost) bb.getHostVM());
@@ -356,8 +385,11 @@ public void afterAnalysis(AfterAnalysisAccess access) {
356385
if (cg.containsKey(deniedMethod)) {
357386
collectViolations(report, deniedMethod,
358387
maxStackDepth, Options.TruffleTCKPermissionsMaxErrors.getValue(),
359-
cg, contextFilters,
388+
cg, contextFilters, collectMode,
360389
new LinkedList<>(), new HashSet<>(), 1, 0);
390+
if (!report.isEmpty() && collectMode == CollectMode.Single) {
391+
break;
392+
}
361393
}
362394
}
363395
if (!report.isEmpty()) {
@@ -367,7 +399,14 @@ public void afterAnalysis(AfterAnalysisAccess access) {
367399
(pw) -> {
368400
StringBuilder builder = new StringBuilder();
369401
for (List<BaseMethodNode> callPath : report) {
402+
boolean privilegedMethod = true;
370403
for (BaseMethodNode call : callPath) {
404+
if (privilegedMethod) {
405+
builder.append("Illegal call to privileged method ");
406+
privilegedMethod = false;
407+
} else {
408+
builder.append(" at ");
409+
}
371410
builder.append(call.asStackTraceElement()).append(System.lineSeparator());
372411
}
373412
builder.append(System.lineSeparator());
@@ -569,6 +608,7 @@ private static boolean isBackTraceOverLanguageMethod(AnalysisMethodNode method,
569608
* @param callGraph call graph obtained from
570609
* {@link PermissionsFeature#callGraph(BigBang, Set, DebugContext, SVMHost)}
571610
* @param contextFiltersParam filters removing known valid calls
611+
* @param collectMode violation collect mode, see {@link Options#TruffleTCKCollectMode}
572612
* @param currentPath current path from a privileged method in a call graph
573613
* @param visited set of already visited methods, these methods are already part of an existing
574614
* report or do not lead to language class
@@ -581,6 +621,7 @@ private int collectViolations(
581621
int maxReports,
582622
Map<BaseMethodNode, Set<BaseMethodNode>> callGraph,
583623
Set<CallGraphFilter> contextFiltersParam,
624+
CollectMode collectMode,
584625
List<BaseMethodNode> currentPath,
585626
Set<BaseMethodNode> visited,
586627
int depth,
@@ -599,7 +640,8 @@ private int collectViolations(
599640
Set<BaseMethodNode> callers = callGraph.get(mNode);
600641
if (depth > maxDepth) {
601642
if (!callers.isEmpty()) {
602-
numReports = collectViolations(report, callers.iterator().next(), maxDepth, maxReports, callGraph, contextFiltersParam, currentPath, visited, depth + 1, numReports);
643+
numReports = collectViolations(report, callers.iterator().next(), maxDepth, maxReports, callGraph, contextFiltersParam, collectMode, currentPath, visited, depth + 1,
644+
numReports);
603645
}
604646
} else if (!isSystemOrSafeClass(mNode)) {
605647
List<BaseMethodNode> callPath = new ArrayList<>(currentPath);
@@ -608,7 +650,10 @@ private int collectViolations(
608650
} else {
609651
for (BaseMethodNode caller : callers) {
610652
if (contextFiltersParam.stream().noneMatch((f) -> f.test(mNode, caller, currentPath))) {
611-
numReports = collectViolations(report, caller, maxDepth, maxReports, callGraph, contextFiltersParam, currentPath, visited, depth + 1, numReports);
653+
numReports = collectViolations(report, caller, maxDepth, maxReports, callGraph, contextFiltersParam, collectMode, currentPath, visited, depth + 1, numReports);
654+
if (numReports > initialNumReports && collectMode != CollectMode.All) {
655+
break;
656+
}
612657
}
613658
}
614659
}

vm/mx.vm/mx_vm_gate.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -599,8 +599,11 @@ def gate_python(tasks):
599599
python_suite.extensions.run_python_unittests(python_svm_image_path)
600600

601601

602-
def _svm_truffle_tck(native_image, language_id, language_distribution=None, fail_on_error=True, print_call_tree=False):
602+
def _svm_truffle_tck(native_image, language_id, language_distribution=None, fail_on_error=True, print_call_tree=False,
603+
additional_options=None):
603604
assert language_distribution, 'Language_distribution must be given'
605+
if additional_options is None:
606+
additional_options = []
604607
dists = [
605608
mx.distribution('substratevm:SVM_TRUFFLE_TCK'),
606609
language_distribution
@@ -631,7 +634,7 @@ def _collect_excludes(suite, suite_import, excludes):
631634
f'-H:TruffleTCKPermissionsReportFile={report_file}',
632635
f'-H:Path={svmbuild}',
633636
'--add-exports=org.graalvm.truffle.runtime/com.oracle.truffle.runtime=ALL-UNNAMED'
634-
] + print_call_tree_options) + [
637+
] + print_call_tree_options + additional_options) + [
635638
'com.oracle.svm.truffle.tck.MockMain'
636639
]
637640
if excludes:
@@ -642,6 +645,9 @@ def _collect_excludes(suite, suite_import, excludes):
642645
with open(report_file, "r") as f:
643646
for line in f.readlines():
644647
message = message + line
648+
message = message + ("\nNote: If the method is not used directly by the language, but is part of the call path "
649+
"because it is used internally by the JDK and introduced by a polymorphic call, consider "
650+
"adding it to `jdk_allowed_methods.json`.")
645651
if fail_on_error:
646652
mx.abort(message)
647653
else:
@@ -679,7 +685,8 @@ def _copy_call_tree(source_folder):
679685
test_language_dist = [d for d in truffle_suite.dists if d.name == 'TRUFFLE_TCK_TESTS_LANGUAGE'][0]
680686
native_image_context, svm = graalvm_svm()
681687
with native_image_context(svm.IMAGE_ASSERTION_FLAGS) as native_image:
682-
result = _svm_truffle_tck(native_image, 'TCKSmokeTestLanguage', test_language_dist, False, True)
688+
result = _svm_truffle_tck(native_image, 'TCKSmokeTestLanguage', test_language_dist, False, True,
689+
['-H:TruffleTCKCollectMode=All'])
683690
privileged_calls = result[0]
684691
reports_folder = result[1]
685692
if not 'Failed: Language TCKSmokeTestLanguage performs following privileged calls' in privileged_calls:

0 commit comments

Comments
 (0)