1 /*
2 * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24
25 package org.graalvm.compiler.core.test;
26
27 import static java.lang.String.format;
28
29 import java.io.ByteArrayOutputStream;
30 import java.io.File;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.lang.reflect.Constructor;
34 import java.lang.reflect.Executable;
35 import java.lang.reflect.Method;
36 import java.net.URL;
37 import java.net.URLClassLoader;
38 import java.nio.file.Files;
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.HashSet;
42 import java.util.LinkedHashMap;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.Objects;
46 import java.util.Set;
47
48 import org.graalvm.compiler.options.OptionDescriptor;
49 import org.graalvm.compiler.options.OptionDescriptors;
50 import org.graalvm.compiler.options.OptionKey;
51 import org.graalvm.compiler.options.OptionsParser;
52 import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
53 import org.junit.Test;
54 import org.objectweb.asm.ClassReader;
55 import org.objectweb.asm.ClassVisitor;
56 import org.objectweb.asm.Label;
57 import org.objectweb.asm.MethodVisitor;
58 import org.objectweb.asm.Opcodes;
59 import org.objectweb.asm.Type;
60
61 /**
62 * Verifies a class declaring one or more {@linkplain OptionKey options} has a class initializer
63 * that only initializes the option(s). This sanity check mitigates the possibility of an option
64 * value being used before being set.
65 */
66 public class OptionsVerifierTest {
67
68 @Test
69 public void verifyOptions() throws IOException {
70 try (Classpath cp = new Classpath()) {
71 HashSet<Class<?>> checked = new HashSet<>();
72 for (OptionDescriptors opts : OptionsParser.getOptionsLoader()) {
73 for (OptionDescriptor desc : opts) {
74 OptionsVerifier.checkClass(desc.getDeclaringClass(), desc, checked, cp);
75 }
76 }
77 }
78 }
79
80 static class Classpath implements AutoCloseable {
81 private final Map<String, Object> entries = new LinkedHashMap<>();
82
83 Classpath() throws IOException {
84 List<String> names = new ArrayList<>(Arrays.asList(System.getProperty("java.class.path").split(File.pathSeparator)));
85 if (JavaVersionUtil.JAVA_SPEC <= 8) {
86 names.addAll(Arrays.asList(System.getProperty("sun.boot.class.path").split(File.pathSeparator)));
87 } else {
88 names.addAll(Arrays.asList(System.getProperty("jdk.module.path").split(File.pathSeparator)));
89 }
90 for (String n : names) {
91 File path = new File(n);
92 if (path.exists()) {
93 if (path.isDirectory()) {
94 entries.put(n, path);
95 } else if (n.endsWith(".jar") || n.endsWith(".zip")) {
96 URL url = new URL("jar", "", "file:" + n + "!/");
97 entries.put(n, new URLClassLoader(new URL[]{url}));
98 }
99 }
100 }
101 }
102
103 @Override
104 public void close() throws IOException {
105 for (Object e : entries.values()) {
106 if (e instanceof URLClassLoader) {
107 ((URLClassLoader) e).close();
108 }
109 }
110 }
111
112 public byte[] getInputStream(String classFilePath) throws IOException {
113 for (Object e : entries.values()) {
114 if (e instanceof File) {
115 File path = new File((File) e, classFilePath.replace('/', File.separatorChar));
116 if (path.exists()) {
117 return Files.readAllBytes(path.toPath());
118 }
119 } else {
120 assert e instanceof URLClassLoader;
121 URLClassLoader ucl = (URLClassLoader) e;
122 try (InputStream in = ucl.getResourceAsStream(classFilePath)) {
123 if (in != null) {
124 ByteArrayOutputStream buffer = new ByteArrayOutputStream();
125 int nRead;
126 byte[] data = new byte[1024];
127 while ((nRead = in.read(data, 0, data.length)) != -1) {
128 buffer.write(data, 0, nRead);
129 }
130 return buffer.toByteArray();
131 }
132 }
133 }
134 }
135 return null;
136 }
137 }
138
139 static final class OptionsVerifier extends ClassVisitor {
140
141 public static void checkClass(Class<?> cls, OptionDescriptor option, Set<Class<?>> checked, Classpath cp) throws IOException {
142 if (!checked.contains(cls)) {
143 checked.add(cls);
144 Class<?> superclass = cls.getSuperclass();
145 if (superclass != null && !superclass.equals(Object.class)) {
146 checkClass(superclass, option, checked, cp);
147 }
148
149 String classFilePath = cls.getName().replace('.', '/') + ".class";
150 ClassReader cr = new ClassReader(Objects.requireNonNull(cp.getInputStream(classFilePath), "Could not find class file for " + cls.getName()));
151
152 ClassVisitor cv = new OptionsVerifier(cls, option);
153 cr.accept(cv, 0);
154 }
155 }
156
157 /**
158 * The option field context of the verification.
159 */
160 private final OptionDescriptor option;
161
162 /**
163 * The class in which {@link #option} is declared or a super-class of that class. This is
164 * the class whose {@code <clinit>} method is being verified.
165 */
166 private final Class<?> cls;
167
168 /**
169 * Source file context for error reporting.
170 */
|
1 /*
2 * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24
25 package org.graalvm.compiler.core.test;
26
27 import static java.lang.String.format;
28
29 import java.io.IOException;
30 import java.lang.reflect.Constructor;
31 import java.lang.reflect.Executable;
32 import java.lang.reflect.Method;
33 import java.util.Arrays;
34 import java.util.HashSet;
35 import java.util.Set;
36
37 import org.graalvm.compiler.options.OptionDescriptor;
38 import org.graalvm.compiler.options.OptionDescriptors;
39 import org.graalvm.compiler.options.OptionKey;
40 import org.graalvm.compiler.options.OptionsParser;
41 import org.graalvm.compiler.serviceprovider.GraalServices;
42 import org.junit.Test;
43 import org.objectweb.asm.ClassReader;
44 import org.objectweb.asm.ClassVisitor;
45 import org.objectweb.asm.Label;
46 import org.objectweb.asm.MethodVisitor;
47 import org.objectweb.asm.Opcodes;
48 import org.objectweb.asm.Type;
49
50 /**
51 * Verifies a class declaring one or more {@linkplain OptionKey options} has a class initializer
52 * that only initializes the option(s). This sanity check mitigates the possibility of an option
53 * value being used before being set.
54 */
55 public class OptionsVerifierTest {
56
57 @Test
58 public void verifyOptions() throws IOException {
59 HashSet<Class<?>> checked = new HashSet<>();
60 for (OptionDescriptors opts : OptionsParser.getOptionsLoader()) {
61 for (OptionDescriptor desc : opts) {
62 OptionsVerifier.checkClass(desc.getDeclaringClass(), desc, checked);
63 }
64 }
65 }
66
67 static final class OptionsVerifier extends ClassVisitor {
68
69 public static void checkClass(Class<?> cls, OptionDescriptor option, Set<Class<?>> checked) throws IOException {
70 if (!checked.contains(cls)) {
71 checked.add(cls);
72 Class<?> superclass = cls.getSuperclass();
73 if (superclass != null && !superclass.equals(Object.class)) {
74 checkClass(superclass, option, checked);
75 }
76
77 GraalServices.getClassfileAsStream(cls);
78 ClassReader cr = new ClassReader(GraalServices.getClassfileAsStream(cls));
79
80 ClassVisitor cv = new OptionsVerifier(cls, option);
81 cr.accept(cv, 0);
82 }
83 }
84
85 /**
86 * The option field context of the verification.
87 */
88 private final OptionDescriptor option;
89
90 /**
91 * The class in which {@link #option} is declared or a super-class of that class. This is
92 * the class whose {@code <clinit>} method is being verified.
93 */
94 private final Class<?> cls;
95
96 /**
97 * Source file context for error reporting.
98 */
|