WALA: Call graph edges missing in programs with reflection set to STRING_ONLY compared to NONE
Hi,
I’ve noticed some (seemingly) strange behavior when running WALA on programs under different reflection settings.
For example, consider the antlr.jar (antlr.zip) program from DaCapo-2006: specifically, the following piece of code from antlr.Tool.doEverything.
try {
ANTLRParser p = new ANTLRParser(tokenBuf, behavior, this);
p.setFilename(grammarFile);
p.grammar();
if (hasError()) {
fatalError("Exiting due to errors.");
}
checkForInvalidArguments(modifiedArgs, cmdLineArgValid);
// Create the right code generator according to the "language" option
CodeGenerator codeGen;
// SAS: created getLanguage() method so subclass can override
// (necessary for VAJ interface)
String codeGenClassName = "antlr." + getLanguage(behavior) + "CodeGenerator";
try {
// HERE
Class codeGenClass = Class.forName(codeGenClassName);
codeGen = (CodeGenerator)codeGenClass.newInstance();
codeGen.setBehavior(behavior);
codeGen.setAnalyzer(analyzer);
codeGen.setTool(this);
codeGen.gen();
}
catch (ClassNotFoundException cnfe) {
panic("Cannot instantiate code-generator: " + codeGenClassName);
}
catch (InstantiationException ie) {
panic("Cannot instantiate code-generator: " + codeGenClassName);
}
catch (IllegalArgumentException ie) {
panic("Cannot instantiate code-generator: " + codeGenClassName);
}
catch (IllegalAccessException iae) {
panic("code-generator class '" + codeGenClassName + "' is not accessible");
}
When I run WALA with the NONE Reflection Option, I get a call graph that includes the calls to Class.forName and Class.newInstance in the inner try block, but not the calls to setBehavior, setAnalyzer, or setTool. Even more strangely, when I run WALA with Reflection set to the STRING_ONLY setting, I don’t even the edges to class.forName or class.newInstance(). Notably, if I compile antlr with Java 8 (the attached version was compiled with Java 11), then the edges to setBehavior, setAnalyzer, and setTool are still missing, but both configurations report the edges to Class.forName and class.newInstance, so maybe this is an issue with some newer JVM bytecode features like invokedynamic? However, I was able to inspect the control flow graph and see that the call to newInstance and forName were reachable.
I’ve noticed this behavior on multiple programs. For example, on hsqldb.jar and hsqldb-deps.jar (hsqldb.zip) we see strange behavior on the following try-catch block in org.hsqldb.TestBase.setUp:
try {
Class.forName("org.hsqldb.jdbcDriver");
} catch (Exception e) {
e.printStackTrace();
System.out.println(this + ".setUp() error: " + e.getMessage());
}
WALA run with the NONE reflection option reports an edge to Throwable.getMessage from the call to Exception.getMessage in the catch block. WALA run with the STRING_ONLY option does not report any outbound edges from this block, and indeed, from the method this block is in at all.
Finally, on pmd.jar (pmd.zip), consider the following method in net.sourceforge.pmd.RuleSetFactory:
private void parseInternallyDefinedRuleNode(RuleSet ruleSet, Node ruleNode)
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Element ruleElement = (Element) ruleNode;
String attribute = ruleElement.getAttribute("class");
Rule rule = (Rule) classLoader.loadClass(attribute).newInstance();
}
the WALA configuration with STRING_ONLY does not report the calls to ClassLoader.loadClass or Class.newInstance on the last line, while the configuration with NONE does.
Any insight as to why this is happening? I’m not sure if this is a bug or expected behavior of the STRING_ONLY option. Thanks!
Austin
About this issue
- Original URL
- State: open
- Created 2 years ago
- Comments: 34 (18 by maintainers)
Commits related to this issue
- Add new reflection test (#1117) Based on discussion in #1116, in particular https://github.com/wala/WALA/issues/1116#issuecomment-1224480683 — committed to wala/WALA by msridhar 2 years ago
Yes, we used ZERO_CFA for these.
Sure. It’s kind of a long file since we made our driver try to support all of WALA’s configurability:
The actual call graph is built and printed in
main. clo is a JCommander command line object; you can see the options we support at https://github.com/amordahl/WALAInterface/blob/main/src/main/java/edu/utdallas/amordahl/CommandLineOptions.java. The pom.xml file is at https://github.com/amordahl/WALAInterface/blob/main/src/main/java/edu/utdallas/amordahl/CommandLineOptions.java; we are using wala 1.5.7.Sure. Here’s a program that exhibits the behavior:
Under STRING_ONLY, WALA does not have an edge to Exception.getMessage(). On NONE, it does. I compiled the program with temurin-jdk 8, and am using the code here to run WALA and print the call graph: https://github.com/amordahl/WALAInterface
No. If I compile the antlr JAR with Java 8, then both STRING_ONLY and NONE show edges to Class.forName and Class.newInstance. If I compile the jar with Java 11, then only NONE has edges to these methods. I don’t think either configuration has edges to
setBehavioretc. under either compilation setting. That’s why I was wondering whether it might have something to do withinvokedynamic.This is tricky, I’ve been trying to do this myself but it has been a difficult task. Here’s a reduced version of hsqldb.jar hsqldb.zip that shows the behavior (only about 300 LoC). Specifically, the configuration with STRING_ONLY misses the edges here, in org.hsqldb.util.ScriptTool.java (this is the decompiled code as produced by IntelliJ):