pascal-lab/Tai-e

"pascal.taie.analysis.graph.icfg.ICFGBuilder.getCFGOf(pascal.taie.language.classes.JMethod)" is null

Closed this issue · 6 comments

Describe the bug

Hi, i use Tai-e to perform an Inter-procedural analysis, (such as InterConstantPropgation). But Every time the option "-scope APP" is spcified, which is default, Tai-e will always report NullPointerException as below:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "pascal.taie.analysis.graph.cfg.CFG.getEntry()" because the return value of "pascal.taie.analysis.graph.icfg.ICFGBuilder.getCFGOf(pascal.taie.language.classes.JMethod)" is null
	at pascal.taie.analysis.graph.icfg.DefaultICFG.getEntryOf(DefaultICFG.java:134)
	at pascal.taie.analysis.graph.icfg.DefaultICFG.getEntryOf(DefaultICFG.java:47)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1707)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
	at pascal.taie.analysis.dataflow.inter.InterSolver.initialize(InterSolver.java:64)
	at pascal.taie.analysis.dataflow.inter.InterSolver.solve(InterSolver.java:56)
	at pascal.taie.analysis.dataflow.inter.AbstractInterDataflowAnalysis.analyze(AbstractInterDataflowAnalysis.java:125)
	at pascal.taie.analysis.dataflow.inter.AbstractInterDataflowAnalysis.analyze(AbstractInterDataflowAnalysis.java:44)
	at pascal.taie.analysis.AnalysisManager.runProgramAnalysis(AnalysisManager.java:148)
	at pascal.taie.analysis.AnalysisManager.runAnalysis(AnalysisManager.java:135)
	at pascal.taie.analysis.AnalysisManager.lambda$execute$0(AnalysisManager.java:104)
	at pascal.taie.util.Timer.runAndCount(Timer.java:93)
	at pascal.taie.analysis.AnalysisManager.lambda$execute$1(AnalysisManager.java:103)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at pascal.taie.analysis.AnalysisManager.execute(AnalysisManager.java:102)
	at pascal.taie.Main.executePlan(Main.java:152)
	at pascal.taie.Main.lambda$main$0(Main.java:61)
	at pascal.taie.util.Timer.lambda$runAndCount$0(Timer.java:112)
	at pascal.taie.util.Timer.runAndCount(Timer.java:93)
	at pascal.taie.util.Timer.runAndCount(Timer.java:111)
	at pascal.taie.util.Timer.runAndCount(Timer.java:107)
	at pascal.taie.Main.main(Main.java:52)

i went deep down to the bug source and noticed that the JMethod arg of the method getCFGOf tended to be methods of implicit-entries defined in AbstractWorldBuilder.java:

    protected static final List<String> implicitEntries = List.of(
            "<java.lang.System: void initializeSystemClass()>",
            "<java.lang.Thread: void <init>(java.lang.ThreadGroup,java.lang.Runnable)>",
            "<java.lang.Thread: void <init>(java.lang.ThreadGroup,java.lang.String)>",
            "<java.lang.Thread: void exit()>",
            "<java.lang.ThreadGroup: void <init>()>",
            "<java.lang.ThreadGroup: void <init>(java.lang.ThreadGroup,java.lang.String)>",
            "<java.lang.ThreadGroup: void uncaughtException(java.lang.Thread,java.lang.Throwable)>",
            "<java.lang.ClassLoader: void <init>()>",
            "<java.lang.ClassLoader: java.lang.Class loadClassInternal(java.lang.String)>",
            "<java.lang.ClassLoader: void checkPackageAccess(java.lang.Class,java.security.ProtectionDomain)>",
            "<java.lang.ClassLoader: void addClass(java.lang.Class)>",
            "<java.lang.ClassLoader: long findNative(java.lang.ClassLoader,java.lang.String)>",
            "<java.security.PrivilegedActionException: void <init>(java.lang.Exception)>"
    );

i did't run with the implicit-entries eliminated since the wiki warns the potential unsoundness, and plus, pta can run perfectly with default options.
i am also relunctant to run Tai-e with option -scpoe REACHABLE since i want all code of app to be analyzed, but it indeed works well.

i also manully modify the field implicitEntries of AbstractWorldBuilder with an empty list, but Tai-e still gives me the same error only with the arg of getCFGOf as methods in Thread or ThreadGroup.

so, i was wondering if there was something that i did wrong or Tai-e really had relevant bug, since it looks quite trivial and no issues have ever been submitted before.

Thanks a lot.

Tai-e arguments

-cp java-benchmarks/dacapo-2006/antlr.jar:java-benchmarks/dacapo-2006/antlr-deps.jar -m dacapo.antlr.Main -java 8 -a inter-const-prop

Runtime environment infomation

OS: MacOS
IDE: Jetbrains IDEA
Tai-e Version: the newest code in master branch.
JDK: 17

This behavior is not a bug. As you correctly pointed out, the recommended solution is to use the -scope REACHABLE option.

Interprocedural analyses typically rely on a call graph to connect call sites and their corresponding callees. Additionally, the call graph also determines which parts of the program are reachable. Analyzing the entire application code within the context of the interprocedural analysis may not be reasonable, as certain portions of the application code may not be reachable according to the call graph. This indicates that they are not connected within the ICFG.

Thanks for reply. So is there any possibility that i can run Interprocedural analyses on the entire application? Or alternatively, any methods that i can run maybe, something like the same analysis again after the first analysis on the residual portions of the application code ? Since i really need to run the Interprocedural analysis on the whole application code even that is not reachable.

If your really need to analyze all application methods within an interprocedural analysis, you must first ensure that they are reachable. This can be accomplished by designating them as entry methods in the pointer analysis, and you just need to create a Plugin and then call Solver.addEntryPoint() (with app methods as arguments) in Plugin.onStart().

For more information about plugin system in the pointer analysis, please refer to Pointer Analysis Framework.

Thanks a lot, i am gonna give it a try.

Your situation sounds a bit unusual. If you find that the reachable method analyzed by the pointer analysis is significantly less than expected, it might be due to reflection. In that case, you need to initiate the appropriate reflection analysis to analyze most of the ANTLR methods. You can try adding reflection-log:java-benchmarks/dacapo-2006/antlr-refl.log to the pta options.

Hi, Sorry for the delay and thanks a lot for the reply. But honestly, i am new to static analysis and not able to understand the reflection analysis you mentioned. and secondly, i assume the part of methods in application may be never reached if they are called only when triggered instead of called by main methods. finally, the solution that i tried works fine for me, so i will stick to it for now.
Thanks again!