Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to only analyze a subset of standard lib from running JVM #1286

Merged
merged 34 commits into from
Jul 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4b45da8
Target JDK 11 without setting the toolchain
msridhar Jun 23, 2023
1f5a8e8
more
msridhar Jun 23, 2023
b205d68
formatting
msridhar Jun 23, 2023
8184a6c
temporarily don't run aggregatedJavadocs, to unblock other CI failures
msridhar Jun 23, 2023
86ba18f
CI on Linux JDK 17
msridhar Jun 24, 2023
e4f7794
handle unresolvable exception types
msridhar Jun 24, 2023
fe98650
hacky kawa fix
msridhar Jun 24, 2023
ec51601
fixes
msridhar Jun 24, 2023
6fdd9fd
spotless
msridhar Jun 24, 2023
694274e
test
msridhar Jun 24, 2023
2a623a0
add constrainTransitivesToThisRelease() at top level
msridhar Jun 24, 2023
cb0cab6
remove file
msridhar Jun 24, 2023
adf8156
Merge branch 'fix-aggregated-javadocs' into Java-17
msridhar Jun 24, 2023
3f3cf34
restore aggregatedJavadocs
msridhar Jun 24, 2023
46e4e14
bump memory for tests
msridhar Jun 24, 2023
b4c18dc
Merge branch 'master' into Java-17
msridhar Jun 24, 2023
d4ae667
add a comment
msridhar Jun 24, 2023
19e08f6
revert change
msridhar Jun 24, 2023
31bbe66
update comment
msridhar Jun 24, 2023
8f39dc9
WIP
msridhar Jun 25, 2023
5498472
Merge branch 'master' into tinker-with-jmod
msridhar Jun 27, 2023
cea6d58
cleanup
msridhar Jun 27, 2023
f28ccc3
Merge branch 'master' into tinker-with-jmod
msridhar Jul 2, 2023
642665c
WIP
msridhar Jul 3, 2023
88f8ad5
Merge branch 'master' into tinker-with-jmod
msridhar Jul 3, 2023
f35a846
fix test
msridhar Jul 3, 2023
3abe48a
Merge branch 'master' into tinker-with-jmod
msridhar Jul 4, 2023
0089956
fewer changes
msridhar Jul 4, 2023
8e810db
test
msridhar Jul 4, 2023
f248d95
WIP
msridhar Jul 5, 2023
9faf3d8
speed up tests
msridhar Jul 5, 2023
2ff09fa
spotless
msridhar Jul 5, 2023
f8b3cda
javadoc
msridhar Jul 5, 2023
be182ca
javadoc fix
msridhar Jul 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -218,10 +218,13 @@ public void processScopeDefLine(AnalysisScope scope, ClassLoader javaLoader, Str
} else if ("loaderImpl".equals(entryType)) {
scope.setLoaderImpl(walaLoader, entryPathname);
} else if ("stdlib".equals(entryType)) {
String[] stdlibs = WalaProperties.getJ2SEJarFiles();
boolean justBase = entryPathname.equals("base");
String[] stdlibs = WalaProperties.getJDKLibraryFiles(justBase);
for (String stdlib : stdlibs) {
scope.addToScope(walaLoader, new JarFile(stdlib, false));
}
} else if ("jdkModule".equals(entryType)) {
scope.addJDKModuleToScope(entryPathname);
} else if (!handleInSubclass(scope, walaLoader, language, entryType, entryPathname)) {
Assertions.UNREACHABLE();
}
Expand All @@ -238,13 +241,29 @@ protected boolean handleInSubclass(
}

/**
* Creates an AnalysisScope containing only the JDK standard libraries. If no explicit JDK library
* paths are given in the WALA properties file, the scope contains all library modules for the
* running JVM.
*
* @param exclusionsFile file holding class hierarchy exclusions. may be null
* @throws IllegalStateException if there are problmes reading wala properties
*/
public AnalysisScope makePrimordialScope(File exclusionsFile) throws IOException {
return readJavaScope(BASIC_FILE, exclusionsFile, MY_CLASSLOADER);
}

/**
* Creates an AnalysisScope containing only the JDK standard libraries. If no explicit JDK library
* paths are given in the WALA properties file, the scope contains only the {@code java.base}
* module for the running JVM.
*
* @param exclusionsFile file holding class hierarchy exclusions. may be null
* @throws IllegalStateException if there are problmes reading wala properties
*/
public AnalysisScope makeBasePrimordialScope(File exclusionsFile) throws IOException {
return readJavaScope("primordial-base.txt", exclusionsFile, MY_CLASSLOADER);
}

/**
* @param classPath class path to analyze, delimited by {@link File#pathSeparator}
* @param exclusionsFile file holding class hierarchy exclusions. may be null
Expand Down
16 changes: 16 additions & 0 deletions core/src/main/java/com/ibm/wala/ipa/callgraph/AnalysisScope.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.PlatformUtil;
import com.ibm.wala.util.collections.FilterIterator;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.HashSetFactory;
Expand All @@ -40,6 +41,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.NotSerializableException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -194,6 +197,19 @@ public void addClassFileToScope(ClassLoaderReference loader, File file)
s.add(new ClassFileModule(file, null));
}

/**
* Adds a module from the Java standard library to the analysis scope.
*
* @param moduleName the name of the module, e.g., {@code "java.sql"}
* @throws IOException if a module by that name cannot successfully be loaded
*/
public void addJDKModuleToScope(String moduleName) throws IOException {
Path path = PlatformUtil.getPathForJDKModule(moduleName);
if (!Files.exists(path)) {
throw new IOException("cannot find jmod file for module " + moduleName + ", tried " + path);
}
addToScope(ClassLoaderReference.Primordial, new JarFile(path.toString(), false));
}
/**
* Add a jar file to the scope via an {@link InputStream}. NOTE: The InputStream should *not* be a
* {@link java.util.jar.JarInputStream}; it should be a regular {@link InputStream} for the raw
Expand Down
26 changes: 20 additions & 6 deletions core/src/main/java/com/ibm/wala/properties/WalaProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,29 +51,43 @@ public final class WalaProperties {
/**
* Determine the classpath noted in wala.properties for J2SE standard libraries
*
* <p>If wala.properties cannot be loaded, returns jar files in boot classpath.
* <p>If wala.properties cannot be loaded, returns library files in boot classpath.
*
* @throws IllegalStateException if jar files cannot be discovered
* @see PlatformUtil#getBootClassPathJars()
* @throws IllegalStateException if library files cannot be discovered
* @see PlatformUtil#getJDKModules(boolean)
*/
public static String[] getJ2SEJarFiles() {
return getJDKLibraryFiles(false);
}

/**
* Determine the classpath noted in wala.properties for J2SE standard libraries
*
* <p>If wala.properties cannot be loaded, returns library files in boot classpath.
*
* @param justBase Only relevant if wala.properties cannot be loaded. If {@code true}, only
* returns the {@code java.base} library from boot classpath. Otherwise, returns all library
* modules from boot classpath.
* @see PlatformUtil#getJDKModules(boolean)
*/
public static String[] getJDKLibraryFiles(boolean justBase) {
Properties p = null;
try {
p = WalaProperties.loadProperties();
} catch (WalaException e) {
return PlatformUtil.getBootClassPathJars();
return PlatformUtil.getJDKModules(justBase);
}

String dir = p.getProperty(WalaProperties.J2SE_DIR);
if (dir == null) {
return PlatformUtil.getBootClassPathJars();
return PlatformUtil.getJDKModules(justBase);
}
if (!new File(dir).isDirectory()) {
System.err.println(
"WARNING: java_runtime_dir "
+ dir
+ " in wala.properties is invalid. Using boot class path instead.");
return PlatformUtil.getBootClassPathJars();
return PlatformUtil.getJDKModules(justBase);
}
return getJarsInDirectory(dir);
}
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/resources/primordial-base.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Primordial,Java,stdlib,base
Primordial,Java,jarFile,primordial.jar.model
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ public void testIO()
throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException {
AnalysisScope scope =
CallGraphTestUtil.makeJ2SEAnalysisScope(
"primordial.txt", CallGraphTestUtil.REGRESSION_EXCLUSIONS);
"primordial-base.txt", CallGraphTestUtil.REGRESSION_EXCLUSIONS);
ClassHierarchy cha = ClassHierarchyFactory.make(scope);
Iterable<Entrypoint> entrypoints = makePrimordialPublicEntrypoints(cha, "java/io");
AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public void testKawaChess()
CallGraph CG =
testKawa(
new ResourceJarFileModule(getClass().getClassLoader().getResource("kawachess.jar")),
"baseAndDesktop.txt",
"main");

Set<CGNode> status =
Expand Down Expand Up @@ -89,6 +90,7 @@ public void testKawaTest()
CallGraph CG =
testKawa(
new ResourceJarFileModule(getClass().getClassLoader().getResource("kawatest.jar")),
"base.txt",
"test");

Set<CGNode> nodes = getNodes(CG, "Ltest", "plusish$V", "(Lgnu/lists/LList;)Ljava/lang/Object;");
Expand All @@ -113,14 +115,15 @@ private static Set<CGNode> getNodes(CallGraph CG, String cls, String method, Str
* #MAX_ITERATIONS} runs of the outer fixed point loop of call graph construction.
*
* @param code the module
* @param scopeFile the scope file to use
* @param main entrypoint method for the call graph
* @return the call graph
*/
private CallGraph testKawa(Module code, String main)
private CallGraph testKawa(Module code, String scopeFile, String main)
throws ClassHierarchyException, IllegalArgumentException, IOException, SecurityException {
AnalysisScope scope =
CallGraphTestUtil.makeJ2SEAnalysisScope(
"base.txt", CallGraphTestUtil.REGRESSION_EXCLUSIONS_FOR_GUI);
scopeFile, CallGraphTestUtil.REGRESSION_EXCLUSIONS_FOR_GUI);
scope.addToScope(
ClassLoaderReference.Application,
new ResourceJarFileModule(getClass().getClassLoader().getResource("kawa.jar")));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,21 @@ public void testJarInputStream() throws IOException, ClassHierarchyException {
TypeReference.findOrCreate(
ClassLoaderReference.Application, "Lorg/apache/bcel/verifier/Verifier")));
}

@Test
public void testBaseScope() throws IOException, ClassHierarchyException {
AnalysisScope scope =
AnalysisScopeReader.instance.readJavaScope(
"primordial-base.txt", null, AnalysisScopeTest.class.getClassLoader());
ClassHierarchy cha = ClassHierarchyFactory.make(scope);
Assert.assertNotNull(
"couldn't find expected class",
cha.lookupClass(
TypeReference.findOrCreate(ClassLoaderReference.Application, "Ljava/util/ArrayList")));
Assert.assertNull(
"found unexpected class",
cha.lookupClass(
TypeReference.findOrCreate(
ClassLoaderReference.Application, "Ljava/awt/AlphaComposite")));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public static void beforeClass() throws Exception {
TestConstants.WALA_TESTDATA,
new FileProvider().getFile("J2SEClassHierarchyExclusions.txt"),
MY_CLASSLOADER);

scope.addJDKModuleToScope("java.sql");
ClassLoaderFactory factory = new ClassLoaderFactoryImpl(scope.getExclusions());

try {
Expand Down
2 changes: 1 addition & 1 deletion core/src/test/resources/base.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Primordial,Java,stdlib,none
Primordial,Java,stdlib,base
Primordial,Java,jarFile,primordial.jar.model
3 changes: 3 additions & 0 deletions core/src/test/resources/baseAndDesktop.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Primordial,Java,stdlib,base
Primordial,Java,jdkModule,java.desktop
Primordial,Java,jarFile,primordial.jar.model
2 changes: 1 addition & 1 deletion core/src/test/resources/hello.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Primordial,Java,stdlib,none
Primordial,Java,stdlib,base
Primordial,Java,jarFile,primordial.jar.model
Application,Java,classFile,hello/Hello.class
Application,Java,sourceFile,hello/Hello.java
2 changes: 1 addition & 1 deletion core/src/test/resources/ocaml_compr.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Primordial,Java,stdlib,none
Primordial,Java,stdlib,base
Primordial,Java,jarFile,primordial.jar.model
Application,Java,jarFile,compr
2 changes: 1 addition & 1 deletion core/src/test/resources/ocaml_hello_hash.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Primordial,Java,stdlib,none
Primordial,Java,stdlib,base
Primordial,Java,jarFile,primordial.jar.model
Application,Java,jarFile,hello_hash.jar
2 changes: 1 addition & 1 deletion core/src/test/resources/wala.testdata.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Primordial,Java,stdlib,none
Primordial,Java,stdlib,base
Primordial,Java,jarFile,primordial.jar.model
Application,Java,jarFile,com.ibm.wala.core.testdata_1.0.0.jar
2 changes: 1 addition & 1 deletion core/src/testFixtures/resources/JLex.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Primordial,Java,stdlib,none
Primordial,Java,stdlib,base
Primordial,Java,jarFile,primordial.jar.model
Application,Java,jarFile,JLex.jar
2 changes: 1 addition & 1 deletion core/src/testFixtures/resources/bcel.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Primordial,Java,stdlib,none
Primordial,Java,stdlib,base
Primordial,Java,jarFile,primordial.jar.model
Application,Java,jarFile,bcel-5.2.jar
2 changes: 1 addition & 1 deletion core/src/testFixtures/resources/java_cup.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Primordial,Java,stdlib,none
Primordial,Java,stdlib,base
Primordial,Java,jarFile,primordial.jar.model
Application,Java,jarFile,java-cup-11a.jar
55 changes: 30 additions & 25 deletions util/src/main/java/com/ibm/wala/util/PlatformUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@
*/
package com.ibm.wala.util;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand Down Expand Up @@ -47,38 +46,44 @@ public static boolean onIKVM() {
}

/**
* get the jars in the boot classpath. TODO test on more JVMs
* Gets the standard JDK modules shipped with the running JDK
*
* @throws IllegalStateException if boot classpath cannot be found
* @param justBase if {@code true}, only include the file corresponding to the {@code java.base}
* module
* @return array of {@code .jmod} module files
* @throws IllegalStateException if modules cannot be found
*/
public static String[] getBootClassPathJars() {
String classpath = null;
String javaVersion = System.getProperty("java.specification.version");
if (!javaVersion.equals("1.8")) {
// java11 support for jmod files
public static String[] getJDKModules(boolean justBase) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm all about that bass, 'bout that bass, no treble
I'm all about that bass, 'bout that bass, no treble
I'm all about that bass, 'bout that bass (bass, bass, bass, bass)

🎶

List<String> jmods;
if (justBase) {
Path basePath = Paths.get(System.getProperty("java.home"), "jmods", "java.base.jmod");
if (!Files.exists(basePath)) {
throw new IllegalStateException("could not find java.base.jmod");
}
jmods = List.of(basePath.toString());
} else {
try (Stream<Path> stream = Files.list(Paths.get(System.getProperty("java.home"), "jmods"))) {
classpath =
String.join(
File.pathSeparator, stream.map(Path::toString).collect(Collectors.toList()));
jmods =
stream
.map(Path::toString)
.filter(p -> p.endsWith(".jmod"))
.collect(Collectors.toList());
} catch (IOException e) {
throw new IllegalStateException(e);
}
} else {
classpath = System.getProperty("sun.boot.class.path");
}
if (classpath == null) {
throw new IllegalStateException("could not find boot classpath");
}
String[] jars = classpath.split(File.pathSeparator);
ArrayList<String> result = new ArrayList<>();
for (String jar : jars) {
if ((jar.endsWith(".jar") || jar.endsWith(".jmod")) && new File(jar).exists()) {
result.add(jar);
}
}
return result.toArray(new String[0]);
return jmods.toArray(new String[0]);
}

/**
* Returns the filesystem path for a JDK module from the running JVM
*
* @param moduleName name of the module, e.g., {@code "java.sql"}
* @return path to the module
*/
public static Path getPathForJDKModule(String moduleName) {
return Paths.get(System.getProperty("java.home"), "jmods", moduleName + ".jmod");
}
/** @return the major version of the Java runtime we are running on. */
public static int getJavaRuntimeVersion() {
String version = System.getProperty("java.version");
Expand Down