8317611: Add a tool like jdeprscan to find usage of restricted methods
Reviewed-by: alanb, ihse, mcimadamore, jlahoda, jwaters
This commit is contained in:
parent
953c35eb5b
commit
cec222e460
@ -51,3 +51,12 @@ $(eval $(call SetupBuildLauncher, jdeprscan, \
|
||||
MAIN_CLASS := com.sun.tools.jdeprscan.Main, \
|
||||
CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS, \
|
||||
))
|
||||
|
||||
################################################################################
|
||||
## Build jnativescan
|
||||
################################################################################
|
||||
|
||||
$(eval $(call SetupBuildLauncher, jnativescan, \
|
||||
MAIN_CLASS := com.sun.tools.jnativescan.Main, \
|
||||
CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS, \
|
||||
))
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -83,7 +83,14 @@ public class JDKPlatformProvider implements PlatformProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformDescription getPlatform(String platformName, String options) {
|
||||
public PlatformDescription getPlatform(String platformName, String options) throws PlatformNotSupported {
|
||||
if (!SUPPORTED_JAVA_PLATFORM_VERSIONS.contains(platformName)) {
|
||||
throw new PlatformNotSupported();
|
||||
}
|
||||
return getPlatformTrusted(platformName);
|
||||
}
|
||||
|
||||
public PlatformDescription getPlatformTrusted(String platformName) {
|
||||
return new PlatformDescriptionImpl(platformName);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -31,11 +31,13 @@
|
||||
module jdk.internal.opt {
|
||||
exports jdk.internal.joptsimple to
|
||||
jdk.jlink,
|
||||
jdk.jshell;
|
||||
jdk.jshell,
|
||||
jdk.jdeps;
|
||||
exports jdk.internal.opt to
|
||||
jdk.compiler,
|
||||
jdk.jartool,
|
||||
jdk.javadoc,
|
||||
jdk.jlink,
|
||||
jdk.jpackage;
|
||||
jdk.jpackage,
|
||||
jdk.jdeps;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -414,7 +414,7 @@ public class Main implements DiagnosticListener<JavaFileObject> {
|
||||
.noneMatch(n -> n.equals(release))) {
|
||||
return false;
|
||||
}
|
||||
JavaFileManager fm = pp.getPlatform(release, "").getFileManager();
|
||||
JavaFileManager fm = pp.getPlatformTrusted(release).getFileManager();
|
||||
List<String> classNames = new ArrayList<>();
|
||||
for (JavaFileObject fo : fm.list(StandardLocation.PLATFORM_CLASS_PATH,
|
||||
"",
|
||||
|
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.tools.jnativescan;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.module.ModuleReader;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
sealed interface ClassFileSource {
|
||||
String moduleName();
|
||||
Path path();
|
||||
|
||||
Stream<byte[]> classFiles(Runtime.Version version) throws IOException;
|
||||
|
||||
record Module(ModuleReference reference) implements ClassFileSource {
|
||||
@Override
|
||||
public String moduleName() {
|
||||
return reference.descriptor().name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path path() {
|
||||
URI location = reference.location().orElseThrow();
|
||||
return Path.of(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<byte[]> classFiles(Runtime.Version version) throws IOException {
|
||||
ModuleReader reader = reference().open();
|
||||
return reader.list()
|
||||
.filter(resourceName -> resourceName.endsWith(".class"))
|
||||
.map(resourceName -> {
|
||||
try (InputStream stream = reader.open(resourceName).orElseThrow()) {
|
||||
return stream.readAllBytes();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}).onClose(() -> {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
record ClassPathJar(Path path) implements ClassFileSource {
|
||||
@Override
|
||||
public String moduleName() {
|
||||
return "ALL-UNNAMED";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<byte[]> classFiles(Runtime.Version version) throws IOException {
|
||||
JarFile jf = new JarFile(path().toFile(), false, ZipFile.OPEN_READ, version);
|
||||
return jf.versionedStream()
|
||||
.filter(je -> je.getName().endsWith(".class"))
|
||||
.map(je -> {
|
||||
try (InputStream stream = jf.getInputStream(je)){
|
||||
return stream.readAllBytes();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}).onClose(() -> {
|
||||
try {
|
||||
jf.close();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
record ClassPathDirectory(Path path) implements ClassFileSource {
|
||||
@Override
|
||||
public String moduleName() {
|
||||
return "ALL-UNNAMED";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<byte[]> classFiles(Runtime.Version version) throws IOException {
|
||||
return Files.walk(path)
|
||||
.filter(file -> Files.isRegularFile(file) && file.toString().endsWith(".class"))
|
||||
.map(file -> {
|
||||
try (InputStream stream = Files.newInputStream(file)){
|
||||
return stream.readAllBytes();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.tools.jnativescan;
|
||||
|
||||
import com.sun.tools.javac.platform.PlatformDescription;
|
||||
import com.sun.tools.javac.platform.PlatformProvider;
|
||||
|
||||
import javax.tools.JavaFileManager;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.StandardLocation;
|
||||
import java.io.IOException;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.ClassModel;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
abstract class ClassResolver implements AutoCloseable {
|
||||
|
||||
static ClassResolver forClassFileSources(List<ClassFileSource> sources, Runtime.Version version) throws IOException {
|
||||
Map<ClassDesc, Info> classMap = new HashMap<>();
|
||||
for (ClassFileSource source : sources) {
|
||||
try (Stream<byte[]> classFiles = source.classFiles(version)) {
|
||||
classFiles.forEach(bytes -> {
|
||||
ClassModel model = ClassFile.of().parse(bytes);
|
||||
ClassDesc desc = model.thisClass().asSymbol();
|
||||
classMap.put(desc, new Info(source, model));
|
||||
});
|
||||
}
|
||||
}
|
||||
return new SimpleClassResolver(classMap);
|
||||
}
|
||||
|
||||
static ClassResolver forSystemModules(Runtime.Version version) {
|
||||
String platformName = String.valueOf(version.feature());
|
||||
PlatformProvider platformProvider = ServiceLoader.load(PlatformProvider.class).findFirst().orElseThrow();
|
||||
PlatformDescription platform;
|
||||
try {
|
||||
platform = platformProvider.getPlatform(platformName, null);
|
||||
} catch (PlatformProvider.PlatformNotSupported e) {
|
||||
throw new JNativeScanFatalError("Release: " + platformName + " not supported", e);
|
||||
}
|
||||
JavaFileManager fm = platform.getFileManager();
|
||||
return new SystemModuleClassResolver(fm);
|
||||
}
|
||||
|
||||
record Info(ClassFileSource source, ClassModel model) {}
|
||||
|
||||
public abstract void forEach(BiConsumer<ClassDesc, ClassResolver.Info> action);
|
||||
public abstract Optional<ClassResolver.Info> lookup(ClassDesc desc);
|
||||
|
||||
@Override
|
||||
public abstract void close() throws IOException;
|
||||
|
||||
private static class SimpleClassResolver extends ClassResolver {
|
||||
|
||||
private final Map<ClassDesc, ClassResolver.Info> classMap;
|
||||
|
||||
public SimpleClassResolver(Map<ClassDesc, Info> classMap) {
|
||||
this.classMap = classMap;
|
||||
}
|
||||
|
||||
public void forEach(BiConsumer<ClassDesc, ClassResolver.Info> action) {
|
||||
classMap.forEach(action);
|
||||
}
|
||||
|
||||
public Optional<ClassResolver.Info> lookup(ClassDesc desc) {
|
||||
return Optional.ofNullable(classMap.get(desc));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {}
|
||||
}
|
||||
|
||||
private static class SystemModuleClassResolver extends ClassResolver {
|
||||
|
||||
private final JavaFileManager platformFileManager;
|
||||
private final Map<String, String> packageToSystemModule;
|
||||
private final Map<ClassDesc, Info> cache = new HashMap<>();
|
||||
|
||||
public SystemModuleClassResolver(JavaFileManager platformFileManager) {
|
||||
this.platformFileManager = platformFileManager;
|
||||
this.packageToSystemModule = packageToSystemModule(platformFileManager);
|
||||
}
|
||||
|
||||
private static Map<String, String> packageToSystemModule(JavaFileManager platformFileManager) {
|
||||
try {
|
||||
Set<JavaFileManager.Location> locations = platformFileManager.listLocationsForModules(
|
||||
StandardLocation.SYSTEM_MODULES).iterator().next();
|
||||
|
||||
Map<String, String> result = new HashMap<>();
|
||||
for (JavaFileManager.Location loc : locations) {
|
||||
JavaFileObject jfo = platformFileManager.getJavaFileForInput(loc, "module-info", JavaFileObject.Kind.CLASS);
|
||||
ModuleDescriptor descriptor = ModuleDescriptor.read(jfo.openInputStream());
|
||||
for (ModuleDescriptor.Exports export : descriptor.exports()) {
|
||||
if (!export.isQualified()) {
|
||||
result.put(export.source(), descriptor.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(BiConsumer<ClassDesc, Info> action) {
|
||||
throw new UnsupportedOperationException("NYI");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Info> lookup(ClassDesc desc) {
|
||||
return Optional.ofNullable(cache.computeIfAbsent(desc, _ -> {
|
||||
String qualName = JNativeScanTask.qualName(desc);
|
||||
String moduleName = packageToSystemModule.get(desc.packageName());
|
||||
if (moduleName != null) {
|
||||
try {
|
||||
JavaFileManager.Location loc = platformFileManager.getLocationForModule(StandardLocation.SYSTEM_MODULES, moduleName);
|
||||
JavaFileObject jfo = platformFileManager.getJavaFileForInput(loc, qualName, JavaFileObject.Kind.CLASS);
|
||||
if (jfo == null) {
|
||||
throw new JNativeScanFatalError("System class can not be found: " + qualName);
|
||||
}
|
||||
ClassModel model = ClassFile.of().parse(jfo.openInputStream().readAllBytes());
|
||||
return new Info(null, model);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
platformFileManager.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.tools.jnativescan;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
// Exception used in case of fatal error that is reasonably expected and handled.
|
||||
public class JNativeScanFatalError extends RuntimeException {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public JNativeScanFatalError(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public JNativeScanFatalError(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public JNativeScanFatalError(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.tools.jnativescan;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.module.Configuration;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ResolvedModule;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
class JNativeScanTask {
|
||||
|
||||
private final PrintWriter out;
|
||||
private final List<Path> classPaths;
|
||||
private final List<Path> modulePaths;
|
||||
private final List<String> cmdRootModules;
|
||||
private final Runtime.Version version;
|
||||
private final Action action;
|
||||
|
||||
public JNativeScanTask(PrintWriter out, List<Path> classPaths, List<Path> modulePaths,
|
||||
List<String> cmdRootModules, Runtime.Version version, Action action) {
|
||||
this.out = out;
|
||||
this.classPaths = classPaths;
|
||||
this.modulePaths = modulePaths;
|
||||
this.version = version;
|
||||
this.action = action;
|
||||
this.cmdRootModules = cmdRootModules;
|
||||
}
|
||||
|
||||
public void run() throws JNativeScanFatalError {
|
||||
List<ClassFileSource> toScan = new ArrayList<>(findAllClassPathJars());
|
||||
|
||||
ModuleFinder moduleFinder = ModuleFinder.of(modulePaths.toArray(Path[]::new));
|
||||
List<String> rootModules = cmdRootModules;
|
||||
if (rootModules.contains("ALL-MODULE-PATH")) {
|
||||
rootModules = allModuleNames(moduleFinder);
|
||||
}
|
||||
Configuration config = systemConfiguration().resolveAndBind(ModuleFinder.of(), moduleFinder, rootModules);
|
||||
for (ResolvedModule m : config.modules()) {
|
||||
toScan.add(new ClassFileSource.Module(m.reference()));
|
||||
}
|
||||
|
||||
SortedMap<ClassFileSource, SortedMap<ClassDesc, List<RestrictedUse>>> allRestrictedMethods;
|
||||
try(ClassResolver classesToScan = ClassResolver.forClassFileSources(toScan, version);
|
||||
ClassResolver systemClassResolver = ClassResolver.forSystemModules(version)) {
|
||||
NativeMethodFinder finder = NativeMethodFinder.create(classesToScan, systemClassResolver);
|
||||
allRestrictedMethods = finder.findAll();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case PRINT -> printNativeAccess(allRestrictedMethods);
|
||||
case DUMP_ALL -> dumpAll(allRestrictedMethods);
|
||||
}
|
||||
}
|
||||
|
||||
private List<ClassFileSource> findAllClassPathJars() throws JNativeScanFatalError {
|
||||
List<ClassFileSource> result = new ArrayList<>();
|
||||
for (Path path : classPaths) {
|
||||
if (isJarFile(path)) {
|
||||
Deque<Path> jarsToScan = new ArrayDeque<>();
|
||||
jarsToScan.offer(path);
|
||||
|
||||
// recursively look for all class path jars, starting at the root jars
|
||||
// in this.classPaths, and recursively following all Class-Path manifest
|
||||
// attributes
|
||||
while (!jarsToScan.isEmpty()) {
|
||||
Path jar = jarsToScan.poll();
|
||||
String[] classPathAttribute = classPathAttribute(jar);
|
||||
Path parentDir = jar.getParent();
|
||||
for (String classPathEntry : classPathAttribute) {
|
||||
Path otherJar = parentDir != null
|
||||
? parentDir.resolve(classPathEntry)
|
||||
: Path.of(classPathEntry);
|
||||
if (Files.exists(otherJar)) {
|
||||
// Class-Path attribute specifies that jars that
|
||||
// are not found are simply ignored. Do the same here
|
||||
jarsToScan.offer(otherJar);
|
||||
}
|
||||
}
|
||||
result.add(new ClassFileSource.ClassPathJar(jar));
|
||||
}
|
||||
} else if (Files.isDirectory(path)) {
|
||||
result.add(new ClassFileSource.ClassPathDirectory(path));
|
||||
} else {
|
||||
throw new JNativeScanFatalError(
|
||||
"Path does not appear to be a jar file, or directory containing classes: " + path);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String[] classPathAttribute(Path jar) {
|
||||
try (JarFile jf = new JarFile(jar.toFile(), false, ZipFile.OPEN_READ, version)) {
|
||||
Manifest manifest = jf.getManifest();
|
||||
if (manifest != null) {
|
||||
String attrib = manifest.getMainAttributes().getValue("Class-Path");
|
||||
if (attrib != null) {
|
||||
return attrib.split("\\s+");
|
||||
}
|
||||
}
|
||||
return new String[0];
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Configuration systemConfiguration() {
|
||||
ModuleFinder systemFinder = ModuleFinder.ofSystem();
|
||||
Configuration system = Configuration.resolve(systemFinder, List.of(Configuration.empty()), ModuleFinder.of(),
|
||||
allModuleNames(systemFinder)); // resolve all of them
|
||||
return system;
|
||||
}
|
||||
|
||||
private List<String> allModuleNames(ModuleFinder finder) {
|
||||
return finder.findAll().stream().map(mr -> mr.descriptor().name()).toList();
|
||||
}
|
||||
|
||||
private void printNativeAccess(SortedMap<ClassFileSource, SortedMap<ClassDesc, List<RestrictedUse>>> allRestrictedMethods) {
|
||||
String nativeAccess = allRestrictedMethods.keySet().stream()
|
||||
.map(ClassFileSource::moduleName)
|
||||
.distinct()
|
||||
.collect(Collectors.joining(","));
|
||||
out.println(nativeAccess);
|
||||
}
|
||||
|
||||
private void dumpAll(SortedMap<ClassFileSource, SortedMap<ClassDesc, List<RestrictedUse>>> allRestrictedMethods) {
|
||||
if (allRestrictedMethods.isEmpty()) {
|
||||
out.println(" <no restricted methods>");
|
||||
} else {
|
||||
allRestrictedMethods.forEach((module, perClass) -> {
|
||||
out.println(module.path() + " (" + module.moduleName() + "):");
|
||||
perClass.forEach((classDesc, restrictedUses) -> {
|
||||
out.println(" " + qualName(classDesc) + ":");
|
||||
restrictedUses.forEach(use -> {
|
||||
switch (use) {
|
||||
case RestrictedUse.NativeMethodDecl(MethodRef nmd) ->
|
||||
out.println(" " + nmd + " is a native method declaration");
|
||||
case RestrictedUse.RestrictedMethodRefs(MethodRef referent, Set<MethodRef> referees) -> {
|
||||
out.println(" " + referent + " references restricted methods:");
|
||||
referees.forEach(referee -> out.println(" " + referee));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isJarFile(Path path) throws JNativeScanFatalError {
|
||||
return Files.exists(path) && Files.isRegularFile(path) && path.toString().endsWith(".jar");
|
||||
}
|
||||
|
||||
public enum Action {
|
||||
DUMP_ALL,
|
||||
PRINT
|
||||
}
|
||||
|
||||
public static String qualName(ClassDesc desc) {
|
||||
String packagePrefix = desc.packageName().isEmpty() ? "" : desc.packageName() + ".";
|
||||
return packagePrefix + desc.displayName();
|
||||
}
|
||||
}
|
234
src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java
Normal file
234
src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.tools.jnativescan;
|
||||
|
||||
import jdk.internal.joptsimple.*;
|
||||
import jdk.internal.opt.CommandLine;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.spi.ToolProvider;
|
||||
|
||||
public class Main {
|
||||
|
||||
private static boolean DEBUG = Boolean.getBoolean("com.sun.tools.jnativescan.DEBUG");
|
||||
|
||||
private static final int SUCCESS_CODE = 0;
|
||||
private static final int FATAL_ERROR_CODE = 1;
|
||||
|
||||
private final PrintWriter out;
|
||||
private final PrintWriter err;
|
||||
|
||||
private Main(PrintWriter out, PrintWriter err) {
|
||||
this.out = out;
|
||||
this.err = err;
|
||||
}
|
||||
|
||||
private void printError(String message) {
|
||||
err.println("ERROR: " + message);
|
||||
}
|
||||
|
||||
private void printUsage() {
|
||||
out.print("""
|
||||
Use 'jnativescan --help' for help
|
||||
""");
|
||||
}
|
||||
|
||||
private void printVersion() {
|
||||
out.println(System.getProperty("java.version"));
|
||||
}
|
||||
|
||||
public int run(String[] args) {
|
||||
if (args.length < 1) {
|
||||
printUsage();
|
||||
return FATAL_ERROR_CODE;
|
||||
}
|
||||
|
||||
try {
|
||||
String[] expandedArgs = expandArgFiles(args);
|
||||
parseOptionsAndRun(expandedArgs);
|
||||
} catch (JNativeScanFatalError fatalError) {
|
||||
printError(fatalError.getMessage());
|
||||
for (Throwable cause = fatalError.getCause();
|
||||
cause instanceof JNativeScanFatalError jNativeScanFatalError;
|
||||
cause = jNativeScanFatalError.getCause()) {
|
||||
err.println("CAUSED BY: " + jNativeScanFatalError.getMessage());
|
||||
}
|
||||
if (DEBUG) {
|
||||
fatalError.printStackTrace(err);
|
||||
}
|
||||
return FATAL_ERROR_CODE;
|
||||
} catch (Throwable e) {
|
||||
printError("Unexpected exception encountered");
|
||||
e.printStackTrace(err);
|
||||
return FATAL_ERROR_CODE;
|
||||
}
|
||||
|
||||
return SUCCESS_CODE;
|
||||
}
|
||||
|
||||
private void parseOptionsAndRun(String[] expandedArgs) throws JNativeScanFatalError {
|
||||
OptionParser parser = new OptionParser(false);
|
||||
OptionSpec<Void> helpOpt = parser.acceptsAll(List.of("?", "h", "help"), "help").forHelp();
|
||||
OptionSpec<Void> versionOpt = parser.accepts("version", "Print version information and exit");
|
||||
OptionSpec<Path> classPathOpt = parser.accepts(
|
||||
"class-path",
|
||||
"The class path as used at runtime")
|
||||
.withRequiredArg()
|
||||
.withValuesSeparatedBy(File.pathSeparatorChar)
|
||||
.withValuesConvertedBy(PARSE_PATH);
|
||||
OptionSpec<Path> modulePathOpt = parser.accepts(
|
||||
"module-path",
|
||||
"The module path as used at runtime")
|
||||
.withRequiredArg()
|
||||
.withValuesSeparatedBy(File.pathSeparatorChar)
|
||||
.withValuesConvertedBy(PARSE_PATH);
|
||||
OptionSpec<Runtime.Version> releaseOpt = parser.accepts(
|
||||
"release",
|
||||
"The runtime version that will run the application")
|
||||
.withRequiredArg()
|
||||
.withValuesConvertedBy(PARSE_VERSION);
|
||||
OptionSpec<String> addModulesOpt = parser.accepts(
|
||||
"add-modules",
|
||||
"List of root modules to scan")
|
||||
.requiredIf(modulePathOpt)
|
||||
.withRequiredArg()
|
||||
.withValuesSeparatedBy(',');
|
||||
OptionSpec<Void> printNativeAccessOpt = parser.accepts(
|
||||
"print-native-access",
|
||||
"print a comma separated list of modules that may perform native access operations." +
|
||||
" ALL-UNNAMED is used to indicate unnamed modules.");
|
||||
|
||||
OptionSet optionSet;
|
||||
try {
|
||||
optionSet = parser.parse(expandedArgs);
|
||||
} catch (OptionException oe) {
|
||||
throw new JNativeScanFatalError("Parsing options failed: " + oe.getMessage(), oe);
|
||||
}
|
||||
|
||||
if (optionSet.nonOptionArguments().size() != 0) {
|
||||
throw new JNativeScanFatalError("jnativescan does not accept positional arguments");
|
||||
}
|
||||
|
||||
if (optionSet.has(helpOpt)) {
|
||||
out.println("""
|
||||
The jnativescan tool can be used to find methods that may access native functionality when
|
||||
run. This includes restricted method calls and 'native' method declarations.
|
||||
""");
|
||||
try {
|
||||
parser.printHelpOn(out);
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (optionSet.has(versionOpt)) {
|
||||
printVersion();
|
||||
return;
|
||||
}
|
||||
|
||||
List<Path> classPathJars = optionSet.valuesOf(classPathOpt);
|
||||
List<Path> modulePaths = optionSet.valuesOf(modulePathOpt);
|
||||
List<String> rootModules = optionSet.valuesOf(addModulesOpt);
|
||||
Runtime.Version version = Optional.ofNullable(optionSet.valueOf(releaseOpt)).orElse(Runtime.version());
|
||||
|
||||
JNativeScanTask.Action action = JNativeScanTask.Action.DUMP_ALL;
|
||||
if (optionSet.has(printNativeAccessOpt)) {
|
||||
action = JNativeScanTask.Action.PRINT;
|
||||
}
|
||||
|
||||
new JNativeScanTask(out, classPathJars, modulePaths, rootModules, version, action).run();
|
||||
}
|
||||
|
||||
private static String[] expandArgFiles(String[] args) throws JNativeScanFatalError {
|
||||
try {
|
||||
return CommandLine.parse(args);
|
||||
} catch (IOException e) { // file not found
|
||||
throw new JNativeScanFatalError(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.exit(new Main.Provider().run(System.out, System.err, args));
|
||||
}
|
||||
|
||||
public static class Provider implements ToolProvider {
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "jnativescan";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int run(PrintWriter out, PrintWriter err, String... args) {
|
||||
return new Main(out, err).run(args);
|
||||
}
|
||||
}
|
||||
|
||||
// where
|
||||
private static final ValueConverter<Path> PARSE_PATH = new ValueConverter<>() {
|
||||
@Override
|
||||
public Path convert(String value) {
|
||||
return Path.of(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Path> valueType() {
|
||||
return Path.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String valuePattern() {
|
||||
return "Path";
|
||||
}
|
||||
};
|
||||
|
||||
private static final ValueConverter<Runtime.Version> PARSE_VERSION = new ValueConverter<>() {
|
||||
@Override
|
||||
public Runtime.Version convert(String value) {
|
||||
try {
|
||||
return Runtime.Version.parse(value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new JNativeScanFatalError("Invalid release: " + value + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Runtime.Version> valueType() {
|
||||
return Runtime.Version.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String valuePattern() {
|
||||
return "Version";
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.tools.jnativescan;
|
||||
|
||||
import java.lang.classfile.MethodModel;
|
||||
import java.lang.classfile.constantpool.MemberRefEntry;
|
||||
import java.lang.classfile.instruction.InvokeInstruction;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
|
||||
record MethodRef(ClassDesc owner, String name, MethodTypeDesc type) {
|
||||
public static MethodRef ofModel(MethodModel model) {
|
||||
return new MethodRef(model.parent().orElseThrow().thisClass().asSymbol(),
|
||||
model.methodName().stringValue(), model.methodTypeSymbol());
|
||||
}
|
||||
|
||||
public static MethodRef ofInvokeInstruction(InvokeInstruction instruction) {
|
||||
return new MethodRef(instruction.owner().asSymbol(),
|
||||
instruction.name().stringValue(), instruction.typeSymbol());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JNativeScanTask.qualName(owner) + "::" + name + type.displayDescriptor();
|
||||
}
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.tools.jnativescan;
|
||||
|
||||
import com.sun.tools.jnativescan.RestrictedUse.NativeMethodDecl;
|
||||
import com.sun.tools.jnativescan.RestrictedUse.RestrictedMethodRefs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.classfile.Attributes;
|
||||
import java.lang.classfile.ClassModel;
|
||||
import java.lang.classfile.MethodModel;
|
||||
import java.lang.classfile.instruction.InvokeInstruction;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.lang.reflect.AccessFlag;
|
||||
import java.util.*;
|
||||
|
||||
class NativeMethodFinder {
|
||||
|
||||
// ct.sym uses this fake name for the restricted annotation instead
|
||||
// see make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java
|
||||
private static final String RESTRICTED_NAME = "Ljdk/internal/javac/Restricted+Annotation;";
|
||||
|
||||
private final Map<MethodRef, Boolean> cache = new HashMap<>();
|
||||
private final ClassResolver classesToScan;
|
||||
private final ClassResolver systemClassResolver;
|
||||
|
||||
private NativeMethodFinder(ClassResolver classesToScan, ClassResolver systemClassResolver) {
|
||||
this.classesToScan = classesToScan;
|
||||
this.systemClassResolver = systemClassResolver;
|
||||
}
|
||||
|
||||
public static NativeMethodFinder create(ClassResolver classesToScan, ClassResolver systemClassResolver) throws JNativeScanFatalError, IOException {
|
||||
return new NativeMethodFinder(classesToScan, systemClassResolver);
|
||||
}
|
||||
|
||||
public SortedMap<ClassFileSource, SortedMap<ClassDesc, List<RestrictedUse>>> findAll() throws JNativeScanFatalError {
|
||||
SortedMap<ClassFileSource, SortedMap<ClassDesc, List<RestrictedUse>>> restrictedMethods
|
||||
= new TreeMap<>(Comparator.comparing(ClassFileSource::path));
|
||||
classesToScan.forEach((_, info) -> {
|
||||
ClassModel classModel = info.model();
|
||||
List<RestrictedUse> perClass = new ArrayList<>();
|
||||
classModel.methods().forEach(methodModel -> {
|
||||
if (methodModel.flags().has(AccessFlag.NATIVE)) {
|
||||
perClass.add(new NativeMethodDecl(MethodRef.ofModel(methodModel)));
|
||||
} else {
|
||||
SortedSet<MethodRef> perMethod = new TreeSet<>(Comparator.comparing(MethodRef::toString));
|
||||
methodModel.code().ifPresent(code -> {
|
||||
try {
|
||||
code.forEach(e -> {
|
||||
switch (e) {
|
||||
case InvokeInstruction invoke -> {
|
||||
MethodRef ref = MethodRef.ofInvokeInstruction(invoke);
|
||||
if (isRestrictedMethod(ref)) {
|
||||
perMethod.add(ref);
|
||||
}
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (JNativeScanFatalError e) {
|
||||
throw new JNativeScanFatalError("Error while processing method: " +
|
||||
MethodRef.ofModel(methodModel), e);
|
||||
}
|
||||
});
|
||||
if (!perMethod.isEmpty()) {
|
||||
perClass.add(new RestrictedMethodRefs(MethodRef.ofModel(methodModel), perMethod));
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!perClass.isEmpty()) {
|
||||
restrictedMethods.computeIfAbsent(info.source(),
|
||||
_ -> new TreeMap<>(Comparator.comparing(JNativeScanTask::qualName)))
|
||||
.put(classModel.thisClass().asSymbol(), perClass);
|
||||
}
|
||||
});
|
||||
return restrictedMethods;
|
||||
}
|
||||
|
||||
private boolean isRestrictedMethod(MethodRef ref) throws JNativeScanFatalError {
|
||||
return cache.computeIfAbsent(ref, methodRef -> {
|
||||
if (methodRef.owner().isArray()) {
|
||||
// no restricted methods in arrays atm, and we can't look them up since they have no class file
|
||||
return false;
|
||||
}
|
||||
Optional<ClassResolver.Info> info = systemClassResolver.lookup(methodRef.owner());
|
||||
if (!info.isPresent()) {
|
||||
return false;
|
||||
}
|
||||
ClassModel classModel = info.get().model();
|
||||
Optional<MethodModel> methodModel = findMethod(classModel, methodRef.name(), methodRef.type());
|
||||
if (!methodModel.isPresent()) {
|
||||
// If we are here, the method was referenced through a subclass of the class containing the actual
|
||||
// method declaration. We could implement a method resolver (that needs to be version aware
|
||||
// as well) to find the method model of the declaration, but it's not really worth it.
|
||||
// None of the restricted methods (atm) are exposed through more than 1 public type, so it's not
|
||||
// possible for user code to reference them through a subclass.
|
||||
return false;
|
||||
}
|
||||
|
||||
return hasRestrictedAnnotation(methodModel.get());
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean hasRestrictedAnnotation(MethodModel method) {
|
||||
return method.findAttribute(Attributes.runtimeVisibleAnnotations())
|
||||
.map(rva -> rva.annotations().stream().anyMatch(ann ->
|
||||
ann.className().stringValue().equals(RESTRICTED_NAME)))
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
private static Optional<MethodModel> findMethod(ClassModel classModel, String name, MethodTypeDesc type) {
|
||||
return classModel.methods().stream()
|
||||
.filter(m -> m.methodName().stringValue().equals(name)
|
||||
&& m.methodType().stringValue().equals(type.descriptorString()))
|
||||
.findFirst();
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.tools.jnativescan;
|
||||
|
||||
import java.util.SortedSet;
|
||||
|
||||
sealed interface RestrictedUse {
|
||||
record RestrictedMethodRefs(MethodRef referent, SortedSet<MethodRef> referees) implements RestrictedUse {}
|
||||
record NativeMethodDecl(MethodRef decl) implements RestrictedUse {}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -28,12 +28,13 @@ import jdk.internal.javac.ParticipatesInPreview;
|
||||
/**
|
||||
* Defines tools for analysing dependencies in Java libraries and programs,
|
||||
* including the <em>{@index jdeps jdeps tool}</em>,
|
||||
* <em>{@index javap javap tool}</em>, and
|
||||
* <em>{@index jdeprscan jdeprscan tool}</em> tools.
|
||||
* <em>{@index javap javap tool}</em>,
|
||||
* <em>{@index jdeprscan jdeprscan tool}</em>, and
|
||||
* <em>{@index jnativescan jnativescan tool}</em> tools.
|
||||
*
|
||||
* <p>
|
||||
* This module provides the equivalent of command-line access to the
|
||||
* <em>javap</em> and <em>jdeps</em> tools via the
|
||||
* <em>javap</em>, <em>jdeps</em>, and <em>jnativescan</em> tools via the
|
||||
* {@link java.util.spi.ToolProvider ToolProvider} service provider
|
||||
* interface (SPI)</p>
|
||||
*
|
||||
@ -49,12 +50,14 @@ import jdk.internal.javac.ParticipatesInPreview;
|
||||
* @toolGuide javap
|
||||
* @toolGuide jdeprscan
|
||||
* @toolGuide jdeps
|
||||
* @toolGuide jnativescan
|
||||
*
|
||||
* @provides java.util.spi.ToolProvider
|
||||
* Use {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("javap")}
|
||||
* or {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("jdeps")}
|
||||
* Use {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("javap")},
|
||||
* {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("jdeps")},
|
||||
* or {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("jnativescan")}
|
||||
* to obtain an instance of a {@code ToolProvider} that provides the equivalent
|
||||
* of command-line access to the {@code javap} or {@code jdeps} tool.
|
||||
* of command-line access to the {@code javap}, {@code jdeps}, {@code jnativescan} tool.
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
@ -63,10 +66,14 @@ import jdk.internal.javac.ParticipatesInPreview;
|
||||
module jdk.jdeps {
|
||||
requires java.compiler;
|
||||
requires jdk.compiler;
|
||||
requires jdk.internal.opt;
|
||||
|
||||
uses com.sun.tools.javac.platform.PlatformProvider;
|
||||
|
||||
exports com.sun.tools.classfile to jdk.jlink;
|
||||
|
||||
provides java.util.spi.ToolProvider with
|
||||
com.sun.tools.javap.Main.JavapToolProvider,
|
||||
com.sun.tools.jdeps.Main.JDepsToolProvider;
|
||||
com.sun.tools.jdeps.Main.JDepsToolProvider,
|
||||
com.sun.tools.jnativescan.Main.Provider;
|
||||
}
|
||||
|
220
src/jdk.jdeps/share/man/jnativescan.1
Normal file
220
src/jdk.jdeps/share/man/jnativescan.1
Normal file
@ -0,0 +1,220 @@
|
||||
.\" Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
.\" DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
.\"
|
||||
.\" This code is free software; you can redistribute it and/or modify it
|
||||
.\" under the terms of the GNU General Public License version 2 only, as
|
||||
.\" published by the Free Software Foundation.
|
||||
.\"
|
||||
.\" This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
.\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
.\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
.\" version 2 for more details (a copy is included in the LICENSE file that
|
||||
.\" accompanied this code).
|
||||
.\"
|
||||
.\" You should have received a copy of the GNU General Public License version
|
||||
.\" 2 along with this work; if not, write to the Free Software Foundation,
|
||||
.\" Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
.\"
|
||||
.\" Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
.\" or visit www.oracle.com if you need additional information or have any
|
||||
.\" questions.
|
||||
.\"
|
||||
.\" Automatically generated by Pandoc 2.19.2
|
||||
.\"
|
||||
.\" Define V font for inline verbatim, using C font in formats
|
||||
.\" that render this, and otherwise B font.
|
||||
.ie "\f[CB]x\f[R]"x" \{\
|
||||
. ftr V B
|
||||
. ftr VI BI
|
||||
. ftr VB B
|
||||
. ftr VBI BI
|
||||
.\}
|
||||
.el \{\
|
||||
. ftr V CR
|
||||
. ftr VI CI
|
||||
. ftr VB CB
|
||||
. ftr VBI CBI
|
||||
.\}
|
||||
.TH "JNATIVESCAN" "1" "2025" "JDK 24-ea" "JDK Commands"
|
||||
.hy
|
||||
.SH NAME
|
||||
.PP
|
||||
jnativescan - static analysis tool that scans one or more jar files for
|
||||
uses of native functionalities, such as restricted method calls or
|
||||
\f[V]native\f[R] method declarations.
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
\f[V]jnativescan\f[R] [\f[I]options\f[R]]
|
||||
.TP
|
||||
\f[I]options\f[R]
|
||||
See \f[B]Options for the jnativescan Command\f[R]
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
The \f[V]jnative\f[R] tool is a static analysis tool provided by the JDK
|
||||
that scans a JAR file for uses of native functionalities, such as
|
||||
restricted method calls or \f[V]native\f[R] method declarations.
|
||||
.PP
|
||||
\f[V]jnativescan\f[R] accepts a runtime class path and module path
|
||||
configuration, as well as a set of root modules, and a target release.
|
||||
It scans the jars on the class and module paths, and reports uses of
|
||||
native functionalities either in a tree like structure, which also
|
||||
identifies that calling classes and methods, or as a list of module
|
||||
names when the \f[V]--print-native-access\f[R] flag is specified.
|
||||
.SH OPTIONS FOR THE JNATIVESCAN COMMAND
|
||||
.PP
|
||||
The following options are available:
|
||||
.TP
|
||||
\f[V]--class-path\f[R] \f[I]path\f[R]
|
||||
Used to specify a list of paths pointing to jar files to be scanned.
|
||||
.PP
|
||||
All jar files specified through this list will be scanned.
|
||||
If a jar file contains a \f[V]Class-Path\f[R] attribute in its manifest,
|
||||
jar files listed there will be scanned as well.
|
||||
Jar files listed in the \f[V]Class-Path\f[R] manifest attribute that can
|
||||
not be found are ignored.
|
||||
All the jar files found are treated as if they belonged to the unnamed
|
||||
module.
|
||||
.TP
|
||||
\f[V]--module-path\f[R] \f[I]path\f[R]
|
||||
Used to specify a list of paths pointing to jar files or directories
|
||||
containing jar files, that the tool can use to find modules that need to
|
||||
be scanned.
|
||||
The list of jar files that will be scanned depends on the
|
||||
\f[V]--add-modules\f[R] option.
|
||||
.RS
|
||||
.PP
|
||||
For both the \f[V]--class-path\f[R] and \f[V]--module-path\f[R] options,
|
||||
\f[I]path\f[R] should be a search path that consists of one or more jar
|
||||
files, separated by the system-specific path separator.
|
||||
For example:
|
||||
.IP \[bu] 2
|
||||
\f[B]Linux and macOS:\f[R]
|
||||
.RS 2
|
||||
.RS
|
||||
.PP
|
||||
\f[V]--class-path /some/foo.jar:/another/different/bar.jar\f[R]
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\f[B]Note:\f[R]
|
||||
.PP
|
||||
On Windows, use a semicolon (\f[V];\f[R]) as the separator instead of a
|
||||
colon (\f[V]:\f[R]).
|
||||
.IP \[bu] 2
|
||||
\f[B]Windows:\f[R]
|
||||
.RS 2
|
||||
.RS
|
||||
.PP
|
||||
\f[V]--class-path C:\[rs]some\[rs]foo.jar;C:\[rs]another\[rs]different\[rs]bar.jar\f[R]
|
||||
.RE
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
\f[V]--add-modules\f[R] \f[I]module[,module...]\f[R]
|
||||
Used to specify a comma-separated list of module names that indicate the
|
||||
root modules to scan.
|
||||
All the root modules will be scanned, as well as any modules that they
|
||||
depend on.
|
||||
This includes dependencies on service implementations specified through
|
||||
the \f[V]uses\f[R] directive in a module\[aq]s \f[V]module-info\f[R]
|
||||
file.
|
||||
All modules found on the module path that provide an implementation of
|
||||
such a service will be scanned as well.
|
||||
.TP
|
||||
\f[V]--release\f[R] \f[I]version\f[R]
|
||||
Used to specify the Java SE release that specifies the set of restricted
|
||||
methods to scan for.
|
||||
For multi-release jar files, this option also indicates the version of
|
||||
class file that should be loaded from the jar.
|
||||
This option should be set to the version of the runtime under which the
|
||||
application is eventually intended to be run.
|
||||
If this flag is omitted, the version of \f[V]jnativescan\f[R] is used as
|
||||
release version, which is the same as the version of the JDK that the
|
||||
tool belongs to.
|
||||
.TP
|
||||
\f[V]--print-native-access\f[R]
|
||||
Print a comma-separated list of module names that use native
|
||||
functionalities, instead of the default tree structure.
|
||||
.TP
|
||||
\f[V]--help\f[R] or \f[V]-h\f[R]
|
||||
Prints out a full help message.
|
||||
.TP
|
||||
\f[V]--version\f[R]
|
||||
Prints out the abbreviated version string of the tool.
|
||||
.SH EXAMPLE OF \f[V]jnativescan\f[R] USE
|
||||
.PP
|
||||
\f[V]jnativescan\f[R] accepts a runtime configuration in the form of a
|
||||
class path, module path, set of root modules, and a target release
|
||||
version.
|
||||
For the class path, the tool will scan all jar files, including those
|
||||
found recursively through the \f[V]Class-Path\f[R] manifest attribute.
|
||||
For the module path, the tool scans all root modules specified through
|
||||
\f[V]--add-modules\f[R], and any (transitive) dependence of the root
|
||||
modules, including any modules that contain service implementations that
|
||||
are used by a scanned module.
|
||||
.PP
|
||||
By default, the tool prints out which jars, classes, and methods use
|
||||
native functionalities, in a tree-like structure.
|
||||
The following is an example output:
|
||||
.IP
|
||||
.nf
|
||||
\f[CB]
|
||||
$ jnativescan --class-path app.jar
|
||||
app.jar (ALL-UNNAMED):
|
||||
foo.Main:
|
||||
foo.Main::main(String[])void references restricted methods:
|
||||
java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment
|
||||
foo.Main::nativeMethod()void is a native method declaration
|
||||
\f[R]
|
||||
.fi
|
||||
.PP
|
||||
\f[V]app.jar (ALL-UNNAMED)\f[R] is the path to the jar file, with the
|
||||
module name in parentheses behind it.
|
||||
Since in this case the jar file appears on the class path,
|
||||
\f[V]ALL-UNNAMED\f[R] is printed to indicate the unnamed module.
|
||||
The second line of the output, \f[V]foo.Main\f[R], indicates that
|
||||
methods using native functionalities were found in the
|
||||
\f[V]foo.Main\f[R] class.
|
||||
The next line:
|
||||
.IP
|
||||
.nf
|
||||
\f[CB]
|
||||
foo.Main::main(String[])void references restricted methods:
|
||||
\f[R]
|
||||
.fi
|
||||
.PP
|
||||
Indicates that the \f[V]main(String[])\f[R] method in the
|
||||
\f[V]foo.Main\f[R] class references a restricted method, which is listed
|
||||
on the following line as:
|
||||
.IP
|
||||
.nf
|
||||
\f[CB]
|
||||
java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment
|
||||
\f[R]
|
||||
.fi
|
||||
.PP
|
||||
Lastly, the text:
|
||||
.IP
|
||||
.nf
|
||||
\f[CB]
|
||||
foo.Main::nativeMethod()void is a native method declaration
|
||||
\f[R]
|
||||
.fi
|
||||
.PP
|
||||
Indicates that the \f[V]foo.Main\f[R] class contains a declaration of a
|
||||
\f[V]native\f[R] method named \f[V]nativeMethod\f[R].
|
||||
.PP
|
||||
If we add \f[V]--print-native-access\f[R] to the example command line,
|
||||
we instead get a list of the names of modules that contain accesses to
|
||||
native functionalities:
|
||||
.IP
|
||||
.nf
|
||||
\f[CB]
|
||||
$ jnativescan --class-path app.jar --print-native-access
|
||||
ALL-UNNAMED
|
||||
\f[R]
|
||||
.fi
|
||||
.PP
|
||||
In this case the output consists of just \f[V]ALL-UNNAMED\f[R], which
|
||||
indicates a jar file on the class path, that is, in the unnamed module,
|
||||
contains an access to native functionalities.
|
@ -141,6 +141,7 @@ public class HelpFlagsTest extends TestHelper {
|
||||
new ToolHelpSpec("jlink", 1, 1, 1, 0, 0, 0, 2), // -?, -h, --help
|
||||
new ToolHelpSpec("jmap", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented.
|
||||
new ToolHelpSpec("jmod", 1, 1, 1, 0, 1, 0, 2), // -?, -h, --help, -help accepted but not documented.
|
||||
new ToolHelpSpec("jnativescan", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented.
|
||||
new ToolHelpSpec("jps", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help
|
||||
new ToolHelpSpec("jrunscript", 1, 1, 1, 0, 1, 1, 7), // -?, -h, --help -help, Documents -help
|
||||
new ToolHelpSpec("jshell", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented.
|
||||
|
@ -63,6 +63,10 @@ langtools_jdeps = \
|
||||
tools/all \
|
||||
tools/jdeps
|
||||
|
||||
langtools_jnativescan = \
|
||||
tools/all \
|
||||
tools/jnativescan
|
||||
|
||||
langtools_slow = \
|
||||
jdk/internal/shellsupport/doc/FullJavadocHelperTest.java
|
||||
|
||||
|
86
test/langtools/tools/jnativescan/JNativeScanTestBase.java
Normal file
86
test/langtools/tools/jnativescan/JNativeScanTestBase.java
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.spi.ToolProvider;
|
||||
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.util.JarUtils;
|
||||
|
||||
public class JNativeScanTestBase {
|
||||
|
||||
public static final String MODULE_PATH = "mods";
|
||||
|
||||
private static final ToolProvider JNATIVESCAN_TOOL = ToolProvider.findFirst("jnativescan")
|
||||
.orElseThrow(() -> new RuntimeException("jnativescan tool not found"));
|
||||
|
||||
public static OutputAnalyzer jnativescan(String... args) {
|
||||
return run(JNATIVESCAN_TOOL, args);
|
||||
}
|
||||
|
||||
private static OutputAnalyzer run(ToolProvider tp, String[] commands) {
|
||||
int rc;
|
||||
StringWriter sw = new StringWriter();
|
||||
StringWriter esw = new StringWriter();
|
||||
|
||||
try (PrintWriter pw = new PrintWriter(sw);
|
||||
PrintWriter epw = new PrintWriter(esw)) {
|
||||
System.out.println("Running " + tp.name() + ", Command: " + Arrays.toString(commands));
|
||||
rc = tp.run(pw, epw, commands);
|
||||
}
|
||||
OutputAnalyzer output = new OutputAnalyzer(sw.toString(), esw.toString(), rc);
|
||||
output.outputTo(System.out);
|
||||
output.errorTo(System.err);
|
||||
return output;
|
||||
}
|
||||
|
||||
public static Path makeModularJar(String moduleName) throws IOException {
|
||||
Path jarPath = Path.of(MODULE_PATH, moduleName + ".jar");
|
||||
Path moduleRoot = moduleRoot(moduleName);
|
||||
JarUtils.createJarFile(jarPath, moduleRoot);
|
||||
return jarPath;
|
||||
}
|
||||
|
||||
public static Path moduleRoot(String name) {
|
||||
return Path.of(System.getProperty("test.module.path")).resolve(name);
|
||||
}
|
||||
|
||||
public static OutputAnalyzer assertSuccess(OutputAnalyzer output) {
|
||||
if (output.getExitValue() != 0) {
|
||||
throw new IllegalStateException("tool run failed");
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
public static OutputAnalyzer assertFailure(OutputAnalyzer output) {
|
||||
if (output.getExitValue() == 0) {
|
||||
throw new IllegalStateException("tool run succeeded");
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
56
test/langtools/tools/jnativescan/TestArrayTypeRefs.java
Normal file
56
test/langtools/tools/jnativescan/TestArrayTypeRefs.java
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @library /test/lib .. ./cases/modules
|
||||
* @build JNativeScanTestBase
|
||||
* cases.classpath.arrayref.App
|
||||
* @run junit TestArrayTypeRefs
|
||||
*/
|
||||
|
||||
import jdk.test.lib.util.JarUtils;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class TestArrayTypeRefs extends JNativeScanTestBase {
|
||||
|
||||
static Path ARRAY_REF;
|
||||
|
||||
@BeforeAll
|
||||
public static void before() throws IOException {
|
||||
ARRAY_REF = Path.of("arrayref.jar");
|
||||
Path testClasses = Path.of(System.getProperty("test.classes", ""));
|
||||
JarUtils.createJarFile(ARRAY_REF, testClasses, Path.of("arrayref", "App.class"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleJarClassPath() {
|
||||
assertSuccess(jnativescan("--class-path", ARRAY_REF.toString()))
|
||||
.stderrShouldBeEmpty()
|
||||
.stdoutShouldContain("<no restricted methods>");
|
||||
}
|
||||
}
|
252
test/langtools/tools/jnativescan/TestJNativeScan.java
Normal file
252
test/langtools/tools/jnativescan/TestJNativeScan.java
Normal file
@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @library /test/lib .. ./cases/modules
|
||||
* @build JNativeScanTestBase
|
||||
* org.singlejar/* org.lib/* org.myapp/* org.service/*
|
||||
* cases.classpath.singlejar.main.Main
|
||||
* cases.classpath.lib.Lib
|
||||
* cases.classpath.app.App
|
||||
* cases.classpath.unnamed_package.UnnamedPackage
|
||||
* @run junit TestJNativeScan
|
||||
*/
|
||||
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.util.JarUtils;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class TestJNativeScan extends JNativeScanTestBase {
|
||||
|
||||
static Path TEST_CLASSES;
|
||||
|
||||
static Path CLASS_PATH_APP;
|
||||
static Path SINGLE_JAR_CLASS_PATH;
|
||||
static Path SINGLE_JAR_MODULAR;
|
||||
static Path ORG_MYAPP;
|
||||
static Path ORG_LIB;
|
||||
static Path UNNAMED_PACKAGE_JAR;
|
||||
static Path LIB_JAR;
|
||||
|
||||
@BeforeAll
|
||||
public static void before() throws IOException {
|
||||
SINGLE_JAR_CLASS_PATH = Path.of("singleJar.jar");
|
||||
TEST_CLASSES = Path.of(System.getProperty("test.classes", ""));
|
||||
JarUtils.createJarFile(SINGLE_JAR_CLASS_PATH, TEST_CLASSES, Path.of("main", "Main.class"));
|
||||
|
||||
LIB_JAR = Path.of("lib.jar");
|
||||
JarUtils.createJarFile(LIB_JAR, TEST_CLASSES, Path.of("lib", "Lib.class"));
|
||||
Manifest manifest = new Manifest();
|
||||
Attributes mainAttrs = manifest.getMainAttributes();
|
||||
mainAttrs.put(Attributes.Name.MANIFEST_VERSION, "1.0"); // need version or other attributes will be ignored
|
||||
mainAttrs.putValue("Class-Path", "lib.jar non-existent.jar");
|
||||
CLASS_PATH_APP = Path.of("app.jar");
|
||||
JarUtils.createJarFile(CLASS_PATH_APP, manifest, TEST_CLASSES, Path.of("app", "App.class"));
|
||||
|
||||
SINGLE_JAR_MODULAR = makeModularJar("org.singlejar");
|
||||
ORG_MYAPP = makeModularJar("org.myapp");
|
||||
ORG_LIB = makeModularJar("org.lib");
|
||||
makeModularJar("org.service");
|
||||
|
||||
UNNAMED_PACKAGE_JAR = Path.of("unnamed_package.jar");
|
||||
JarUtils.createJarFile(UNNAMED_PACKAGE_JAR, TEST_CLASSES, Path.of("UnnamedPackage.class"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleJarClassPath() {
|
||||
assertSuccess(jnativescan("--class-path", SINGLE_JAR_CLASS_PATH.toString()))
|
||||
.stderrShouldBeEmpty()
|
||||
.stdoutShouldContain("ALL-UNNAMED")
|
||||
.stdoutShouldContain("main.Main")
|
||||
.stdoutShouldContain("main.Main::m()void is a native method declaration")
|
||||
.stdoutShouldContain("main.Main::main(String[])void references restricted methods")
|
||||
.stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleJarModulePath() {
|
||||
assertSuccess(jnativescan("--module-path", MODULE_PATH, "--add-modules", "org.singlejar"))
|
||||
.stderrShouldBeEmpty()
|
||||
.stdoutShouldContain("org.singlejar")
|
||||
.stdoutShouldContain("org.singlejar.main.Main")
|
||||
.stdoutShouldContain("org.singlejar.main.Main::m()void is a native method declaration")
|
||||
.stdoutShouldContain("org.singlejar.main.Main::main(String[])void references restricted methods")
|
||||
.stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithDepModule() {
|
||||
assertSuccess(jnativescan("--module-path", MODULE_PATH, "--add-modules", "org.myapp"))
|
||||
.stderrShouldBeEmpty()
|
||||
.stdoutShouldContain("org.lib")
|
||||
.stdoutShouldContain("org.lib.Lib")
|
||||
.stdoutShouldContain("org.lib.Lib::m()void is a native method declaration")
|
||||
.stdoutShouldContain("org.lib.Lib::doIt()void references restricted methods")
|
||||
.stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment")
|
||||
.stdoutShouldContain("org.service")
|
||||
.stdoutShouldContain("org.service.ServiceImpl")
|
||||
.stdoutShouldContain("org.service.ServiceImpl::m()void is a native method declaration")
|
||||
.stdoutShouldContain("org.service.ServiceImpl::doIt()void references restricted methods")
|
||||
.stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllModulePath() {
|
||||
assertSuccess(jnativescan("--module-path", MODULE_PATH, "--add-modules", "ALL-MODULE-PATH"))
|
||||
.stderrShouldBeEmpty()
|
||||
.stdoutShouldContain("org.singlejar")
|
||||
.stdoutShouldContain("org.lib")
|
||||
.stdoutShouldContain("org.service");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassPathAttribute() {
|
||||
assertSuccess(jnativescan("--class-path", CLASS_PATH_APP.toString()))
|
||||
.stderrShouldBeEmpty()
|
||||
.stdoutShouldContain("ALL-UNNAMED")
|
||||
.stdoutShouldContain("lib.Lib")
|
||||
.stdoutShouldContain("lib.Lib::m()void is a native method declaration")
|
||||
.stdoutShouldContain("lib.Lib::doIt()void references restricted methods")
|
||||
.stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidRelease() {
|
||||
assertFailure(jnativescan("--module-path", MODULE_PATH, "--add-modules", "ALL-MODULE-PATH", "--release", "asdf"))
|
||||
.stderrShouldContain("Invalid release");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReleaseNotSupported() {
|
||||
assertFailure(jnativescan("--module-path", MODULE_PATH, "--add-modules", "ALL-MODULE-PATH", "--release", "9999999"))
|
||||
.stderrShouldContain("Release: 9999999 not supported");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileDoesNotExist() {
|
||||
assertFailure(jnativescan("--class-path", "non-existent.jar"))
|
||||
.stderrShouldContain("Path does not appear to be a jar file, or directory containing classes");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testModuleNotAJarFile() {
|
||||
String modulePath = moduleRoot("org.myapp").toString() + File.pathSeparator + ORG_LIB.toString();
|
||||
assertSuccess(jnativescan("--module-path", modulePath,
|
||||
"--add-modules", "ALL-MODULE-PATH"))
|
||||
.stdoutShouldContain("lib.Lib")
|
||||
.stdoutShouldContain("lib.Lib::m()void is a native method declaration")
|
||||
.stdoutShouldContain("lib.Lib::doIt()void references restricted methods")
|
||||
.stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrintNativeAccess() {
|
||||
assertSuccess(jnativescan("--module-path", MODULE_PATH,
|
||||
"-add-modules", "org.singlejar,org.myapp",
|
||||
"--print-native-access"))
|
||||
.stdoutShouldMatch("org.lib,org.service,org.singlejar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoDuplicateNames() {
|
||||
String classPath = SINGLE_JAR_CLASS_PATH + File.pathSeparator + CLASS_PATH_APP;
|
||||
OutputAnalyzer output = assertSuccess(jnativescan("--class-path", classPath, "--print-native-access"));
|
||||
String[] moduleNames = output.getStdout().split(",");
|
||||
Set<String> names = new HashSet<>();
|
||||
for (String name : moduleNames) {
|
||||
assertTrue(names.add(name.strip()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnnamedPackage() {
|
||||
assertSuccess(jnativescan("--class-path", UNNAMED_PACKAGE_JAR.toString()))
|
||||
.stderrShouldBeEmpty()
|
||||
.stdoutShouldContain("ALL-UNNAMED")
|
||||
.stdoutShouldNotContain(".UnnamedPackage")
|
||||
.stdoutShouldContain("UnnamedPackage")
|
||||
.stdoutShouldContain("UnnamedPackage::m()void is a native method declaration")
|
||||
.stdoutShouldContain("UnnamedPackage::main(String[])void references restricted methods")
|
||||
.stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPositionalArguments() {
|
||||
assertFailure(jnativescan("foo"))
|
||||
.stdoutShouldBeEmpty()
|
||||
.stderrShouldContain("jnativescan does not accept positional arguments");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingRootModules() {
|
||||
assertFailure(jnativescan("--module-path", MODULE_PATH))
|
||||
.stdoutShouldBeEmpty()
|
||||
.stderrShouldContain("Missing required option(s) [add-modules]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassPathDirectory() {
|
||||
assertSuccess(jnativescan("--class-path", TEST_CLASSES.toString()))
|
||||
.stderrShouldBeEmpty()
|
||||
.stdoutShouldContain("ALL-UNNAMED")
|
||||
.stdoutShouldContain("UnnamedPackage")
|
||||
.stdoutShouldContain("UnnamedPackage::m()void is a native method declaration")
|
||||
.stdoutShouldContain("UnnamedPackage::main(String[])void references restricted methods")
|
||||
.stdoutShouldContain("main.Main")
|
||||
.stdoutShouldContain("main.Main::m()void is a native method declaration")
|
||||
.stdoutShouldContain("main.Main::main(String[])void references restricted methods")
|
||||
.stdoutShouldContain("lib.Lib")
|
||||
.stdoutShouldContain("lib.Lib::m()void is a native method declaration")
|
||||
.stdoutShouldContain("lib.Lib::doIt()void references restricted methods")
|
||||
.stdoutShouldContain("java.lang.foreign.MemorySegment::reinterpret(long)MemorySegment");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleClassPathJars() {
|
||||
// make sure all of these are reported, even when they are all in the ALL-UNNAMED module
|
||||
String classPath = UNNAMED_PACKAGE_JAR
|
||||
+ File.pathSeparator + SINGLE_JAR_CLASS_PATH
|
||||
+ File.pathSeparator + LIB_JAR;
|
||||
assertSuccess(jnativescan("--class-path", classPath))
|
||||
.stderrShouldBeEmpty()
|
||||
.stdoutShouldContain("ALL-UNNAMED")
|
||||
.stdoutShouldContain("UnnamedPackage")
|
||||
.stdoutShouldContain(UNNAMED_PACKAGE_JAR.toString())
|
||||
.stdoutShouldContain("lib.Lib")
|
||||
.stdoutShouldContain(LIB_JAR.toString())
|
||||
.stdoutShouldContain("main.Main")
|
||||
.stdoutShouldContain(SINGLE_JAR_CLASS_PATH.toString());
|
||||
}
|
||||
}
|
60
test/langtools/tools/jnativescan/TestMissingSystemClass.java
Normal file
60
test/langtools/tools/jnativescan/TestMissingSystemClass.java
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @library /test/lib .. ./cases/modules
|
||||
* @build JNativeScanTestBase
|
||||
* @compile --release 20 cases/classpath/missingsystem/App.java
|
||||
* @run junit TestMissingSystemClass
|
||||
*/
|
||||
|
||||
import jdk.test.lib.util.JarUtils;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class TestMissingSystemClass extends JNativeScanTestBase {
|
||||
|
||||
static Path MISSING_SYSTEM;
|
||||
|
||||
@BeforeAll
|
||||
public static void before() throws IOException {
|
||||
MISSING_SYSTEM = Path.of("missingsystem.jar");
|
||||
Path testClasses = Path.of(System.getProperty("test.classes", ""));
|
||||
JarUtils.createJarFile(MISSING_SYSTEM, testClasses, Path.of("missingsystem", "App.class"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleJarClassPath() {
|
||||
assertFailure(jnativescan("--class-path", MISSING_SYSTEM.toString(), "--release", "21"))
|
||||
.stdoutShouldBeEmpty()
|
||||
.stderrShouldContain("Error while processing method")
|
||||
.stderrShouldContain("missingsystem.App::main(String[])void")
|
||||
.stderrShouldContain("CAUSED BY:")
|
||||
.stderrShouldContain("System class can not be found")
|
||||
.stderrShouldContain("java.lang.Compiler");
|
||||
}
|
||||
}
|
56
test/langtools/tools/jnativescan/TestSubclassRefs.java
Normal file
56
test/langtools/tools/jnativescan/TestSubclassRefs.java
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @library /test/lib .. ./cases/modules
|
||||
* @build JNativeScanTestBase
|
||||
* cases.classpath.subclassref.App
|
||||
* @run junit TestSubclassRefs
|
||||
*/
|
||||
|
||||
import jdk.test.lib.util.JarUtils;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class TestSubclassRefs extends JNativeScanTestBase {
|
||||
|
||||
static Path SUBCLASS_REF;
|
||||
|
||||
@BeforeAll
|
||||
public static void before() throws IOException {
|
||||
SUBCLASS_REF = Path.of("subclassref.jar");
|
||||
Path testClasses = Path.of(System.getProperty("test.classes", ""));
|
||||
JarUtils.createJarFile(SUBCLASS_REF, testClasses, Path.of("subclassref", "App.class"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleJarClassPath() {
|
||||
assertSuccess(jnativescan("--class-path", SUBCLASS_REF.toString()))
|
||||
.stderrShouldBeEmpty()
|
||||
.stdoutShouldContain("<no restricted methods>");
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package app;
|
||||
|
||||
import lib.Lib;
|
||||
|
||||
public class App {
|
||||
public static void main(String[] args) {
|
||||
Lib.doIt();
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package arrayref;
|
||||
|
||||
public class App {
|
||||
public static void main(String[] args) {
|
||||
// reference an array method to see that
|
||||
// RestrictedMethodFinder correctly handles
|
||||
// references to array methods
|
||||
args.clone();
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package lib;
|
||||
|
||||
import java.lang.foreign.MemorySegment;
|
||||
|
||||
public class Lib {
|
||||
public static void doIt() {
|
||||
MemorySegment.ofAddress(1234).reinterpret(10);
|
||||
}
|
||||
|
||||
private static native void m();
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package missingsystem;
|
||||
|
||||
public class App {
|
||||
public static void main(String[] args) {
|
||||
// this class was present in Java 20, but removed in 21
|
||||
// if we compile with --release 20, but run jnativescan
|
||||
// with --release 21, we should get an error
|
||||
java.lang.Compiler.enable();
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package main;
|
||||
|
||||
import java.lang.foreign.*;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
MemorySegment.ofAddress(1234).reinterpret(10);
|
||||
}
|
||||
|
||||
private static native void m();
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package subclassref;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class App {
|
||||
public static void main(String[] args) {
|
||||
List<String> l = List.of(args);
|
||||
l.stream(); // List does not declare stream()
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.lang.foreign.*;
|
||||
|
||||
public class UnnamedPackage {
|
||||
public static void main(String[] args) {
|
||||
MemorySegment.ofAddress(1234).reinterpret(10);
|
||||
}
|
||||
|
||||
private static native void m();
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
module org.lib {
|
||||
exports org.lib;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package org.lib;
|
||||
|
||||
import java.lang.foreign.*;
|
||||
|
||||
public class Lib {
|
||||
public static void doIt() {
|
||||
MemorySegment.ofAddress(1234).reinterpret(10);
|
||||
}
|
||||
|
||||
private static native void m();
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.lib;
|
||||
|
||||
public interface Service {
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
module org.myapp {
|
||||
requires org.lib;
|
||||
|
||||
uses org.lib.Service;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package org.myapp.main;
|
||||
|
||||
import org.lib.Lib;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
Lib.doIt();
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
module org.service {
|
||||
requires org.lib;
|
||||
|
||||
provides org.lib.Service with org.service.ServiceImpl;
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.service;
|
||||
|
||||
import org.lib.Service;
|
||||
|
||||
import java.lang.foreign.MemorySegment;
|
||||
|
||||
public class ServiceImpl implements Service {
|
||||
public void doIt() {
|
||||
MemorySegment.ofAddress(1234).reinterpret(10);
|
||||
}
|
||||
|
||||
private native void m();
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
module org.singlejar {
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package org.singlejar.main;
|
||||
|
||||
import java.lang.foreign.*;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
MemorySegment.ofAddress(1234).reinterpret(10);
|
||||
}
|
||||
|
||||
private static native void m();
|
||||
}
|
Loading…
Reference in New Issue
Block a user