Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/sun/reflect/CallerSensitive/CallerSensitiveFinder.java
38841 views
/*1* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import com.sun.tools.classfile.*;24import com.sun.tools.jdeps.ClassFileReader;25import static com.sun.tools.classfile.ConstantPool.*;26import java.io.File;27import java.io.IOException;28import java.nio.file.FileVisitResult;29import java.nio.file.Files;30import java.nio.file.Path;31import java.nio.file.Paths;32import java.nio.file.SimpleFileVisitor;33import java.nio.file.attribute.BasicFileAttributes;34import java.util.ArrayList;35import java.util.List;36import java.util.Set;37import java.util.concurrent.Callable;38import java.util.concurrent.ExecutionException;39import java.util.concurrent.ExecutorService;40import java.util.concurrent.Executors;41import java.util.concurrent.FutureTask;4243/*44* @test45* @bug 801011746* @summary Verify if CallerSensitive methods are annotated with47* sun.reflect.CallerSensitive annotation48* @build CallerSensitiveFinder49* @run main/othervm/timeout=900 -mx600m CallerSensitiveFinder50*/51public class CallerSensitiveFinder {52private static int numThreads = 3;53private static boolean verbose = false;54public static void main(String[] args) throws Exception {55List<Path> classes = new ArrayList<>();56String testclasses = System.getProperty("test.classes", ".");57int i = 0;58while (i < args.length) {59String arg = args[i++];60if (arg.equals("-v")) {61verbose = true;62} else {63Path p = Paths.get(testclasses, arg);64if (!p.toFile().exists()) {65throw new IllegalArgumentException(arg + " does not exist");66}67classes.add(p);68}69}70if (classes.isEmpty()) {71classes.addAll(PlatformClassPath.getJREClasses());72}73CallerSensitiveFinder csfinder = new CallerSensitiveFinder();7475List<String> errors = csfinder.run(classes);76if (!errors.isEmpty()) {77throw new RuntimeException(errors.size() +78" caller-sensitive methods are missing @CallerSensitive annotation");79}80}8182private final List<String> csMethodsMissingAnnotation = new ArrayList<>();83private final ReferenceFinder finder;84public CallerSensitiveFinder() {85this.finder = new ReferenceFinder(getFilter(), getVisitor());86}8788private ReferenceFinder.Filter getFilter() {89final String classname = "sun/reflect/Reflection";90final String method = "getCallerClass";91return new ReferenceFinder.Filter() {92public boolean accept(ConstantPool cpool, CPRefInfo cpref) {93try {94CONSTANT_NameAndType_info nat = cpref.getNameAndTypeInfo();95return cpref.getClassName().equals(classname) && nat.getName().equals(method);96} catch (ConstantPoolException ex) {97throw new RuntimeException(ex);98}99}100};101}102103private ReferenceFinder.Visitor getVisitor() {104return new ReferenceFinder.Visitor() {105public void visit(ClassFile cf, Method m, List<CPRefInfo> refs) {106try {107String name = String.format("%s#%s %s", cf.getName(),108m.getName(cf.constant_pool),109m.descriptor.getValue(cf.constant_pool));110if (!CallerSensitiveFinder.isCallerSensitive(m, cf.constant_pool)) {111csMethodsMissingAnnotation.add(name);112System.err.println("Missing @CallerSensitive: " + name);113} else {114if (verbose) {115System.out.format("@CS %s%n", name);116}117}118} catch (ConstantPoolException ex) {119throw new RuntimeException(ex);120}121}122};123}124125public List<String> run(List<Path> classes) throws IOException, InterruptedException,126ExecutionException, ConstantPoolException127{128ExecutorService pool = Executors.newFixedThreadPool(numThreads);129for (Path path : classes) {130ClassFileReader reader = ClassFileReader.newInstance(path);131for (ClassFile cf : reader.getClassFiles()) {132String classFileName = cf.getName();133// for each ClassFile134// parse constant pool to find matching method refs135// parse each method (caller)136// - visit and find method references matching the given method name137pool.submit(getTask(cf));138}139}140waitForCompletion();141pool.shutdown();142return csMethodsMissingAnnotation;143}144145private static final String CALLER_SENSITIVE_ANNOTATION = "Lsun/reflect/CallerSensitive;";146private static boolean isCallerSensitive(Method m, ConstantPool cp)147throws ConstantPoolException148{149RuntimeAnnotations_attribute attr =150(RuntimeAnnotations_attribute)m.attributes.get(Attribute.RuntimeVisibleAnnotations);151int index = 0;152if (attr != null) {153for (int i = 0; i < attr.annotations.length; i++) {154Annotation ann = attr.annotations[i];155String annType = cp.getUTF8Value(ann.type_index);156if (CALLER_SENSITIVE_ANNOTATION.equals(annType)) {157return true;158}159}160}161return false;162}163164private final List<FutureTask<Void>> tasks = new ArrayList<FutureTask<Void>>();165private FutureTask<Void> getTask(final ClassFile cf) {166FutureTask<Void> task = new FutureTask<Void>(new Callable<Void>() {167public Void call() throws Exception {168finder.parse(cf);169return null;170}171});172tasks.add(task);173return task;174}175176private void waitForCompletion() throws InterruptedException, ExecutionException {177for (FutureTask<Void> t : tasks) {178t.get();179}180System.out.println("Parsed " + tasks.size() + " classfiles");181}182183static class PlatformClassPath {184static List<Path> getJREClasses() throws IOException {185List<Path> result = new ArrayList<Path>();186Path home = Paths.get(System.getProperty("java.home"));187188if (home.endsWith("jre")) {189// jar files in <javahome>/jre/lib190// skip <javahome>/lib191result.addAll(addJarFiles(home.resolve("lib")));192} else if (home.resolve("lib").toFile().exists()) {193// either a JRE or a jdk build image194File classes = home.resolve("classes").toFile();195if (classes.exists() && classes.isDirectory()) {196// jdk build outputdir197result.add(classes.toPath());198}199// add other JAR files200result.addAll(addJarFiles(home.resolve("lib")));201} else {202throw new RuntimeException("\"" + home + "\" not a JDK home");203}204return result;205}206207static List<Path> addJarFiles(final Path root) throws IOException {208final List<Path> result = new ArrayList<Path>();209final Path ext = root.resolve("ext");210Files.walkFileTree(root, new SimpleFileVisitor<Path>() {211@Override212public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)213throws IOException {214if (dir.equals(root) || dir.equals(ext)) {215return FileVisitResult.CONTINUE;216} else {217// skip other cobundled JAR files218return FileVisitResult.SKIP_SUBTREE;219}220}221222@Override223public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)224throws IOException {225File f = file.toFile();226String fn = f.getName();227// parse alt-rt.jar as well228if (fn.endsWith(".jar") && !fn.equals("jfxrt.jar")) {229result.add(file);230}231return FileVisitResult.CONTINUE;232}233});234return result;235}236}237}238239240