From 0d4de8a71f063e44618f43ddd862a91aed647f48 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Wed, 4 Oct 2023 09:36:53 +0000 Subject: [PATCH] 8316971: Add Lint warning for restricted method calls Reviewed-by: ihse, vromero --- make/modules/java.base/Java.gmk | 2 +- make/test/BuildMicrobenchmark.gmk | 2 +- .../com/sun/tools/javac/code/Flags.java | 7 ++- .../com/sun/tools/javac/code/Lint.java | 7 ++- .../com/sun/tools/javac/code/Symtab.java | 2 + .../com/sun/tools/javac/comp/Annotate.java | 5 ++ .../com/sun/tools/javac/comp/Attr.java | 1 + .../com/sun/tools/javac/comp/Check.java | 15 +++++ .../com/sun/tools/javac/jvm/ClassReader.java | 6 ++ .../tools/javac/resources/compiler.properties | 5 ++ .../tools/javac/resources/javac.properties | 3 + .../share/classes/module-info.java | 1 + .../tools/javac/RestrictedMethods.java | 55 +++++++++++++++++++ .../tools/javac/RestrictedMethods.out | 9 +++ .../tools/javac/diags/examples.not-yet.txt | 3 + 15 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 test/langtools/tools/javac/RestrictedMethods.java create mode 100644 test/langtools/tools/javac/RestrictedMethods.out diff --git a/make/modules/java.base/Java.gmk b/make/modules/java.base/Java.gmk index 90350557b37..729f7b19f6d 100644 --- a/make/modules/java.base/Java.gmk +++ b/make/modules/java.base/Java.gmk @@ -23,7 +23,7 @@ # questions. # -DISABLED_WARNINGS_java += this-escape +DISABLED_WARNINGS_java += this-escape restricted DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' diff --git a/make/test/BuildMicrobenchmark.gmk b/make/test/BuildMicrobenchmark.gmk index d1013a89233..c0484cba30f 100644 --- a/make/test/BuildMicrobenchmark.gmk +++ b/make/test/BuildMicrobenchmark.gmk @@ -91,7 +91,7 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \ TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \ SMALL_JAVA := false, \ CLASSPATH := $(MICROBENCHMARK_CLASSPATH), \ - DISABLED_WARNINGS := this-escape processing rawtypes cast serial preview, \ + DISABLED_WARNINGS := restricted this-escape processing rawtypes cast serial preview, \ SRC := $(MICROBENCHMARK_SRC), \ BIN := $(MICROBENCHMARK_CLASSES), \ JAVAC_FLAGS := --add-exports java.base/sun.security.util=ALL-UNNAMED \ diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java index 8799f315067..8856654aed3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java @@ -389,13 +389,18 @@ public class Flags { */ public static final long SEALED = 1L<<62; // ClassSymbols + /** + * Flag to indicate restricted method declaration. + */ + public static final long RESTRICTED = 1L<<62; // MethodSymbols + /** * Flag to indicate that the class/interface was declared with the non-sealed modifier. */ public static final long NON_SEALED = 1L<<63; // ClassSymbols /** - * Describe modifier flags as they migh appear in source code, i.e., + * Describe modifier flags as they might appear in source code, i.e., * separated by spaces and in the order suggested by JLS 8.1.1. */ public static String toSource(long flags) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java index 0ed37e98b8a..e9d64a6ad72 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java @@ -335,7 +335,12 @@ public class Lint /** * Warn about use of preview features. */ - PREVIEW("preview"); + PREVIEW("preview"), + + /** + * Warn about use of restricted methods. + */ + RESTRICTED("restricted"); LintCategory(String option) { this(option, false); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java index 9f0cb59eff0..8e270dec387 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java @@ -220,6 +220,7 @@ public class Symtab { public final Type functionalInterfaceType; public final Type previewFeatureType; public final Type previewFeatureInternalType; + public final Type restrictedType; public final Type typeDescriptorType; public final Type recordType; public final Type switchBootstrapsType; @@ -610,6 +611,7 @@ public class Symtab { functionalInterfaceType = enterClass("java.lang.FunctionalInterface"); previewFeatureType = enterClass("jdk.internal.javac.PreviewFeature"); previewFeatureInternalType = enterSyntheticAnnotation("jdk.internal.PreviewFeature+Annotation"); + restrictedType = enterClass("jdk.internal.javac.Restricted"); typeDescriptorType = enterClass("java.lang.invoke.TypeDescriptor"); recordType = enterClass("java.lang.Record"); switchBootstrapsType = enterClass("java.lang.runtime.SwitchBootstraps"); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java index 8e6a3774df7..40ba3152958 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java @@ -379,6 +379,11 @@ public class Annotate { && types.isSameType(c.type, syms.valueBasedType)) { toAnnotate.flags_field |= Flags.VALUE_BASED; } + + if (!c.type.isErroneous() + && types.isSameType(c.type, syms.restrictedType)) { + toAnnotate.flags_field |= Flags.RESTRICTED; + } } List buf = List.nil(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index d7313ea2067..4b44be198d1 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -4742,6 +4742,7 @@ public class Attr extends JCTree.Visitor { new ResultInfo(resultInfo.pkind, resultInfo.pt.getReturnType(), resultInfo.checkContext, resultInfo.checkMode), env, TreeInfo.args(env.tree), resultInfo.pt.getParameterTypes(), resultInfo.pt.getTypeArguments()); + chk.checkRestricted(tree.pos(), sym); break; } case PCK: case ERR: diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java index d5706e703c5..fb0359e4464 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java @@ -283,6 +283,15 @@ public class Check { preview.reportPreviewWarning(pos, Warnings.DeclaredUsingPreview(kindName(sym), sym)); } + /** Log a preview warning. + * @param pos Position to be used for error reporting. + * @param msg A Warning describing the problem. + */ + public void warnRestrictedAPI(DiagnosticPosition pos, Symbol sym) { + if (lint.isEnabled(LintCategory.RESTRICTED)) + log.warning(LintCategory.RESTRICTED, pos, Warnings.RestrictedMethod(sym.enclClass(), sym)); + } + /** Warn about unchecked operation. * @param pos Position to be used for error reporting. * @param msg A string describing the problem. @@ -3850,6 +3859,12 @@ public class Check { } } + void checkRestricted(DiagnosticPosition pos, Symbol s) { + if (s.kind == MTH && (s.flags() & RESTRICTED) != 0) { + deferredLintHandler.report(() -> warnRestrictedAPI(pos, s)); + } + } + /* ************************************************************************* * Check for recursive annotation elements. **************************************************************************/ diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index 7189dc5fe33..0bc7f8994f6 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -1509,6 +1509,9 @@ public class ClassReader { } else if (proxy.type.tsym.flatName() == syms.valueBasedInternalType.tsym.flatName()) { Assert.check(sym.kind == TYP); sym.flags_field |= VALUE_BASED; + } else if (proxy.type.tsym.flatName() == syms.restrictedType.tsym.flatName()) { + Assert.check(sym.kind == MTH); + sym.flags_field |= RESTRICTED; } else { if (proxy.type.tsym == syms.annotationTargetType.tsym) { target = proxy; @@ -1522,6 +1525,9 @@ public class ClassReader { setFlagIfAttributeTrue(proxy, sym, names.reflective, PREVIEW_REFLECTIVE); } else if (proxy.type.tsym == syms.valueBasedType.tsym && sym.kind == TYP) { sym.flags_field |= VALUE_BASED; + } else if (proxy.type.tsym == syms.restrictedType.tsym) { + Assert.check(sym.kind == MTH); + sym.flags_field |= RESTRICTED; } proxies.append(proxy); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index 78b24f14bb9..1ff2f8d9314 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -1917,6 +1917,11 @@ compiler.err.is.preview=\ compiler.warn.is.preview.reflective=\ {0} is a reflective preview API and may be removed in a future release. +# 0: symbol, 1: symbol +compiler.warn.restricted.method=\ + {0}.{1} is a restricted method.\n\ + (Restricted methods are unsafe and, if used incorrectly, might crash the Java runtime or corrupt memory) + # 0: symbol compiler.warn.has.been.deprecated.module=\ module {0} has been deprecated diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties index 4d7326d7882..d9bd05ba62a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties @@ -282,6 +282,9 @@ javac.opt.Xlint.desc.varargs=\ javac.opt.Xlint.desc.preview=\ Warn about use of preview language features. +javac.opt.Xlint.desc.restricted=\ + Warn about use of restricted methods. + javac.opt.Xlint.desc.synchronization=\ Warn about synchronization attempts on instances of value-based classes. diff --git a/src/jdk.compiler/share/classes/module-info.java b/src/jdk.compiler/share/classes/module-info.java index 79f2b8f2704..c8716233c0f 100644 --- a/src/jdk.compiler/share/classes/module-info.java +++ b/src/jdk.compiler/share/classes/module-info.java @@ -173,6 +173,7 @@ import javax.tools.StandardLocation; * {@code preview} use of preview language features * {@code rawtypes} use of raw types * {@code removal} use of API that has been marked for removal + * {@code restricted} use of restricted methods * {@code requires-automatic} use of automatic modules in the {@code requires} clauses * {@code requires-transitive-automatic} automatic modules in {@code requires transitive} * {@code serial} {@link java.base/java.io.Serializable Serializable} classes diff --git a/test/langtools/tools/javac/RestrictedMethods.java b/test/langtools/tools/javac/RestrictedMethods.java new file mode 100644 index 00000000000..4e3670f551c --- /dev/null +++ b/test/langtools/tools/javac/RestrictedMethods.java @@ -0,0 +1,55 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8316971 + * @summary Smoke test for restricted method call warnings + * @compile/fail/ref=RestrictedMethods.out -Xlint:restricted -Werror -XDrawDiagnostics --enable-preview --source ${jdk.version} RestrictedMethods.java + * @compile -Werror --enable-preview --source ${jdk.version} RestrictedMethods.java + */ + +import java.lang.foreign.MemorySegment; +import java.util.function.Function; + +class RestrictedMethods { + + MemorySegment warn = MemorySegment.NULL.reinterpret(10); // warning here + @SuppressWarnings("restricted") + MemorySegment suppressed = MemorySegment.NULL.reinterpret(10); // no warning here + + Function warn_ref = MemorySegment.NULL::reinterpret; // warning here + + @SuppressWarnings("restricted") + Function suppressed_ref = MemorySegment.NULL::reinterpret; // no warning here + + void testWarn() { + MemorySegment.NULL.reinterpret(10); // warning here + } + + @SuppressWarnings("restricted") + void testSuppressed() { + MemorySegment.NULL.reinterpret(10); // no warning here + } + + Function testWarnRef() { + return MemorySegment.NULL::reinterpret; // warning here + } + + @SuppressWarnings("restricted") + Function testSuppressedRef() { + return MemorySegment.NULL::reinterpret; // no warning here + } + + @SuppressWarnings("restricted") + static class Nested { + MemorySegment suppressedNested = MemorySegment.NULL.reinterpret(10); // no warning here + + Function suppressedNested_ref = MemorySegment.NULL::reinterpret; // no warning here + + void testSuppressedNested() { + MemorySegment.NULL.reinterpret(10); // no warning here + } + + Function testSuppressedNestedRef() { + return MemorySegment.NULL::reinterpret; // no warning here + } + } +} diff --git a/test/langtools/tools/javac/RestrictedMethods.out b/test/langtools/tools/javac/RestrictedMethods.out new file mode 100644 index 00000000000..abf4e1ee1fb --- /dev/null +++ b/test/langtools/tools/javac/RestrictedMethods.out @@ -0,0 +1,9 @@ +RestrictedMethods.java:14:44: compiler.warn.restricted.method: java.lang.foreign.MemorySegment, reinterpret(long) +RestrictedMethods.java:18:49: compiler.warn.restricted.method: java.lang.foreign.MemorySegment, reinterpret(long) +RestrictedMethods.java:24:27: compiler.warn.restricted.method: java.lang.foreign.MemorySegment, reinterpret(long) +RestrictedMethods.java:33:16: compiler.warn.restricted.method: java.lang.foreign.MemorySegment, reinterpret(long) +- compiler.err.warnings.and.werror +- compiler.note.preview.filename: RestrictedMethods.java, DEFAULT +- compiler.note.preview.recompile +1 error +4 warnings diff --git a/test/langtools/tools/javac/diags/examples.not-yet.txt b/test/langtools/tools/javac/diags/examples.not-yet.txt index 983469b78c2..7245c10aa01 100644 --- a/test/langtools/tools/javac/diags/examples.not-yet.txt +++ b/test/langtools/tools/javac/diags/examples.not-yet.txt @@ -215,3 +215,6 @@ compiler.misc.illegal.signature # the compiler can # this one needs a forged class file to be reproduced compiler.err.annotation.unrecognized.attribute.name + +# this one is transitional (waiting for FFM API to exit preview) +compiler.warn.restricted.method