Skip to content

Commit

Permalink
Merge pull request #178 from policeman-tools/dev/issue177
Browse files Browse the repository at this point in the history
Fix false positives in JDK-17 with RandomSupport
  • Loading branch information
uschindler authored Apr 23, 2021
2 parents ac754c4 + fe7737d commit f214716
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 123 deletions.
38 changes: 19 additions & 19 deletions src/main/java/de/thetaphi/forbiddenapis/Checker.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ public static enum Option {
final EnumSet<Option> options;

/** Classes to check: key is the binary name (dotted) */
final Map<String,ClassSignature> classesToCheck = new HashMap<>();
final Map<String,ClassMetadata> classesToCheck = new HashMap<>();
/** Cache of loaded classes: key is the binary name (dotted) */
final Map<String,ClassSignature> classpathClassCache = new HashMap<>();
final Map<String,ClassMetadata> classpathClassCache = new HashMap<>();

final Signatures forbiddenSignatures;

Expand Down Expand Up @@ -185,7 +185,7 @@ public Checker(Logger logger, ClassLoader loader, EnumSet<Option> options) {
}

/** Loads the class from Java9's module system and uses reflection to get methods and fields. */
private ClassSignature loadClassFromJigsaw(String classname) throws IOException {
private ClassMetadata loadClassFromJigsaw(String classname) throws IOException {
if (method_Class_getModule == null || method_Module_getName == null) {
return null; // not Jigsaw Module System
}
Expand All @@ -200,7 +200,7 @@ private ClassSignature loadClassFromJigsaw(String classname) throws IOException
return null; // not found
}

return new ClassSignature(clazz, AsmUtils.isRuntimeModule(moduleName));
return new ClassMetadata(clazz, AsmUtils.isRuntimeModule(moduleName));
}

private boolean isRuntimePath(URL url) throws IOException {
Expand Down Expand Up @@ -233,9 +233,9 @@ private boolean isRuntimeClass(URLConnection conn) throws IOException {

/** Reads a class (binary name) from the given {@link ClassLoader}. If not found there, falls back to the list of classes to be checked. */
@Override
public ClassSignature getClassFromClassLoader(final String clazz) throws ClassNotFoundException,IOException {
public ClassMetadata getClassFromClassLoader(final String clazz) throws ClassNotFoundException,IOException {
if (classpathClassCache.containsKey(clazz)) {
final ClassSignature c = classpathClassCache.get(clazz);
final ClassMetadata c = classpathClassCache.get(clazz);
if (c == null) {
throw new ClassNotFoundException(clazz);
}
Expand All @@ -255,7 +255,7 @@ public ClassSignature getClassFromClassLoader(final String clazz) throws ClassNo
// if class is too new for this JVM, we try to load it as Class<?> via Jigsaw
// (only if it's a runtime class):
if (isRuntimeClass) {
final ClassSignature c = loadClassFromJigsaw(clazz);
final ClassMetadata c = loadClassFromJigsaw(clazz);
if (c != null) {
classpathClassCache.put(clazz, c);
return c;
Expand All @@ -265,18 +265,18 @@ public ClassSignature getClassFromClassLoader(final String clazz) throws ClassNo
"The class file format of '%s' (loaded from location '%s') is too recent to be parsed by ASM.",
clazz, url.toExternalForm()));
}
final ClassSignature c = new ClassSignature(cr, isRuntimeClass, false);
final ClassMetadata c = new ClassMetadata(cr, isRuntimeClass, false);
classpathClassCache.put(clazz, c);
return c;
} else {
final ClassSignature c = loadClassFromJigsaw(clazz);
final ClassMetadata c = loadClassFromJigsaw(clazz);
if (c != null) {
classpathClassCache.put(clazz, c);
return c;
}
}
// try to get class from our list of classes we are checking:
final ClassSignature c = classesToCheck.get(clazz);
final ClassMetadata c = classesToCheck.get(clazz);
if (c != null) {
classpathClassCache.put(clazz, c);
return c;
Expand All @@ -288,7 +288,7 @@ public ClassSignature getClassFromClassLoader(final String clazz) throws ClassNo
}

@Override
public ClassSignature lookupRelatedClass(String internalName, String internalNameOrig) {
public ClassMetadata lookupRelatedClass(String internalName, String internalNameOrig) {
final Type type = Type.getObjectType(internalName);
if (type.getSort() != Type.OBJECT) {
return null;
Expand Down Expand Up @@ -361,8 +361,8 @@ public void addClassToCheck(final InputStream in, String name) throws IOExceptio
throw new IllegalArgumentException(String.format(Locale.ENGLISH,
"The class file format of '%s' is too recent to be parsed by ASM.", name));
}
final String binaryName = Type.getObjectType(reader.getClassName()).getClassName();
classesToCheck.put(binaryName, new ClassSignature(reader, false, true));
final ClassMetadata metadata = new ClassMetadata(reader, false, true);
classesToCheck.put(metadata.getBinaryClassName(), metadata);
}

/** Parses and adds a class from the given file to the list of classes to check. Does not log anything. */
Expand Down Expand Up @@ -407,11 +407,11 @@ public void addSuppressAnnotation(String annoName) {
}

/** Parses a class and checks for valid method invocations */
private int checkClass(final ClassReader reader, Pattern suppressAnnotationsPattern) throws ForbiddenApiException {
final String className = Type.getObjectType(reader.getClassName()).getClassName();
final ClassScanner scanner = new ClassScanner(this, forbiddenSignatures, suppressAnnotationsPattern);
private int checkClass(ClassMetadata c, Pattern suppressAnnotationsPattern) throws ForbiddenApiException {
final String className = c.getBinaryClassName();
final ClassScanner scanner = new ClassScanner(c, this, forbiddenSignatures, suppressAnnotationsPattern);
try {
reader.accept(scanner, ClassReader.SKIP_FRAMES);
c.getReader().accept(scanner, ClassReader.SKIP_FRAMES);
} catch (RelatedClassLoadingException rcle) {
final Exception cause = rcle.getException();
final StringBuilder msg = new StringBuilder()
Expand Down Expand Up @@ -456,8 +456,8 @@ public void run() throws ForbiddenApiException {
logger.info("Scanning classes for violations...");
int errors = 0;
final Pattern suppressAnnotationsPattern = AsmUtils.glob2Pattern(suppressAnnotations.toArray(new String[suppressAnnotations.size()]));
for (final ClassSignature c : classesToCheck.values()) {
errors += checkClass(c.getReader(), suppressAnnotationsPattern);
for (final ClassMetadata c : classesToCheck.values()) {
errors += checkClass(c, suppressAnnotationsPattern);
}

final String message = String.format(Locale.ENGLISH,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,23 @@

/** Utility class that is used to get an overview of all fields and implemented
* methods of a class. It make the signatures available as Sets. */
final class ClassSignature implements Constants {
final class ClassMetadata implements Constants {
private ClassReader reader;

public final boolean isRuntimeClass, isNonPortableRuntime;
public final boolean isRuntimeClass, isNonPortableRuntime, isInterface;
public final Set<Method> methods;
public final Set<String> fields, signaturePolymorphicMethods;
public final String className, superName;
public final String[] interfaces;

/** Builds the information from an ASM ClassReader */
public ClassSignature(final ClassReader classReader, boolean isRuntimeClass, boolean withReader) {
public ClassMetadata(final ClassReader classReader, boolean isRuntimeClass, boolean withReader) {
this.reader = withReader ? classReader : null;
this.isRuntimeClass = isRuntimeClass;
this.className = classReader.getClassName();
this.superName = classReader.getSuperName();
this.interfaces = classReader.getInterfaces();
this.isInterface = (classReader.getAccess() & Opcodes.ACC_INTERFACE) != 0;
final Set<Method> methods = new HashSet<>();
final Set<String> fields = new HashSet<>();
final Set<String> signaturePolymorphicMethods = new HashSet<>();
Expand Down Expand Up @@ -80,7 +81,7 @@ public FieldVisitor visitField(int access, String name, String desc, String sign
}

/** Alternative ctor that can be used to build the information via reflection from an already loaded class. Useful for Java 9 Jigsaw. */
public ClassSignature(final Class<?> clazz, boolean isRuntimeClass) {
public ClassMetadata(final Class<?> clazz, boolean isRuntimeClass) {
this.reader = null; // no reader available!
this.isRuntimeClass = isRuntimeClass;
this.className = Type.getType(clazz).getInternalName();
Expand All @@ -91,6 +92,7 @@ public ClassSignature(final Class<?> clazz, boolean isRuntimeClass) {
for (int i = 0; i < interfClasses.length; i++) {
this.interfaces[i] = Type.getType(interfClasses[i]).getInternalName();
}
this.isInterface = clazz.isInterface();
final Set<Method> methods = new HashSet<>();
final Set<String> fields = new HashSet<>();
final Set<String> signaturePolymorphicMethods = new HashSet<>();
Expand Down
Loading

0 comments on commit f214716

Please sign in to comment.