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, \
|
MAIN_CLASS := com.sun.tools.jdeprscan.Main, \
|
||||||
CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS, \
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -83,7 +83,14 @@ public class JDKPlatformProvider implements PlatformProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -31,11 +31,13 @@
|
|||||||
module jdk.internal.opt {
|
module jdk.internal.opt {
|
||||||
exports jdk.internal.joptsimple to
|
exports jdk.internal.joptsimple to
|
||||||
jdk.jlink,
|
jdk.jlink,
|
||||||
jdk.jshell;
|
jdk.jshell,
|
||||||
|
jdk.jdeps;
|
||||||
exports jdk.internal.opt to
|
exports jdk.internal.opt to
|
||||||
jdk.compiler,
|
jdk.compiler,
|
||||||
jdk.jartool,
|
jdk.jartool,
|
||||||
jdk.javadoc,
|
jdk.javadoc,
|
||||||
jdk.jlink,
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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))) {
|
.noneMatch(n -> n.equals(release))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
JavaFileManager fm = pp.getPlatform(release, "").getFileManager();
|
JavaFileManager fm = pp.getPlatformTrusted(release).getFileManager();
|
||||||
List<String> classNames = new ArrayList<>();
|
List<String> classNames = new ArrayList<>();
|
||||||
for (JavaFileObject fo : fm.list(StandardLocation.PLATFORM_CLASS_PATH,
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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,
|
* Defines tools for analysing dependencies in Java libraries and programs,
|
||||||
* including the <em>{@index jdeps jdeps tool}</em>,
|
* including the <em>{@index jdeps jdeps tool}</em>,
|
||||||
* <em>{@index javap javap tool}</em>, and
|
* <em>{@index javap javap tool}</em>,
|
||||||
* <em>{@index jdeprscan jdeprscan tool}</em> tools.
|
* <em>{@index jdeprscan jdeprscan tool}</em>, and
|
||||||
|
* <em>{@index jnativescan jnativescan tool}</em> tools.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* This module provides the equivalent of command-line access to the
|
* 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
|
* {@link java.util.spi.ToolProvider ToolProvider} service provider
|
||||||
* interface (SPI)</p>
|
* interface (SPI)</p>
|
||||||
*
|
*
|
||||||
@ -49,12 +50,14 @@ import jdk.internal.javac.ParticipatesInPreview;
|
|||||||
* @toolGuide javap
|
* @toolGuide javap
|
||||||
* @toolGuide jdeprscan
|
* @toolGuide jdeprscan
|
||||||
* @toolGuide jdeps
|
* @toolGuide jdeps
|
||||||
|
* @toolGuide jnativescan
|
||||||
*
|
*
|
||||||
* @provides java.util.spi.ToolProvider
|
* @provides java.util.spi.ToolProvider
|
||||||
* Use {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("javap")}
|
* Use {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("javap")},
|
||||||
* or {@link java.util.spi.ToolProvider#findFirst ToolProvider.findFirst("jdeps")}
|
* {@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
|
* 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
|
* @moduleGraph
|
||||||
* @since 9
|
* @since 9
|
||||||
@ -63,10 +66,14 @@ import jdk.internal.javac.ParticipatesInPreview;
|
|||||||
module jdk.jdeps {
|
module jdk.jdeps {
|
||||||
requires java.compiler;
|
requires java.compiler;
|
||||||
requires jdk.compiler;
|
requires jdk.compiler;
|
||||||
|
requires jdk.internal.opt;
|
||||||
|
|
||||||
|
uses com.sun.tools.javac.platform.PlatformProvider;
|
||||||
|
|
||||||
exports com.sun.tools.classfile to jdk.jlink;
|
exports com.sun.tools.classfile to jdk.jlink;
|
||||||
|
|
||||||
provides java.util.spi.ToolProvider with
|
provides java.util.spi.ToolProvider with
|
||||||
com.sun.tools.javap.Main.JavapToolProvider,
|
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("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("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("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("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("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.
|
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/all \
|
||||||
tools/jdeps
|
tools/jdeps
|
||||||
|
|
||||||
|
langtools_jnativescan = \
|
||||||
|
tools/all \
|
||||||
|
tools/jnativescan
|
||||||
|
|
||||||
langtools_slow = \
|
langtools_slow = \
|
||||||
jdk/internal/shellsupport/doc/FullJavadocHelperTest.java
|
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