rohanpadhye / vasco

An inter-procedural data-flow analysis framework using value-based context sensitivity
GNU Lesser General Public License v2.1
88 stars 35 forks source link

java.lang.RuntimeException occured during SignTest #19

Closed kimgimkigi closed 3 years ago

kimgimkigi commented 3 years ago

Hi guys

I'm trying to perform SignTest in open source projects and it goes to java.lang.RuntimeException. Error occurred in the middle stage of SignTest.

My java command

java -cp vascos.jar:soot.jar:rt.jar:junit.jar:jfreechart-1.2.0-pre1.jar:slf4j.jar:slf4j-simple.jar:guava-19.0.jar vasco.soot.examples.SignTest org.jfree.chart.plot.junit.PlotPackageTests

While SignTest, exception occurred after this stages,

---------------------------------------
IN = {l1=_|_}
$stack2 = 2147483647 - l1
OUT = {l1=_|_, $stack2=_|_}
---------------------------------------
IN = {l1=_|_, $stack2=_|_}
if $stack2 >= 0 goto (branch)
OUT = {l1=_|_, $stack2=_|_}
---------------------------------------
IN = {l1=_|_, $stack2=_|_}
$stack4 = new java.lang.OutOfMemoryError
OUT = {l1=_|_, $stack2=_|_}
---------------------------------------
IN = {l1=_|_, $stack2=_|_}
specialinvoke $stack4.<java.lang.OutOfMemoryError: void <init>()>()
[NEW] X16 -> X17 <java.lang.OutOfMemoryError: void <init>()> 
ENTRY(X17) = {}
OUT = {l1=_|_, $stack2=_|_}
---------------------------------------
IN = {}
l0 := @this: java.lang.OutOfMemoryError
OUT = {}
---------------------------------------
IN = {}
specialinvoke l0.<java.lang.VirtualMachineError: void <init>()>()
[NEW] X17 -> X18 <java.lang.VirtualMachineError: void <init>()> 
ENTRY(X18) = {}
OUT = {}
---------------------------------------
IN = {}
l0 := @this: java.lang.VirtualMachineError
OUT = {}
---------------------------------------
IN = {}
specialinvoke l0.<java.lang.Error: void <init>()>()
[NEW] X18 -> X19 <java.lang.Error: void <init>()> 
ENTRY(X19) = {}
OUT = {}
---------------------------------------
IN = {}
l0 := @this: java.lang.Error
OUT = {}
---------------------------------------
IN = {}
specialinvoke l0.<java.lang.Throwable: void <init>()>()
[NEW] X19 -> X20 <java.lang.Throwable: void <init>()> 
ENTRY(X20) = {}
OUT = {}
---------------------------------------
IN = {}
l0 := @this: java.lang.Throwable
OUT = {}
---------------------------------------
IN = {}
specialinvoke l0.<java.lang.Object: void <init>()>()
[HIT] X20 -> X4 <java.lang.Object: void <init>()> 
EXIT(X4) = {}
OUT = {}
---------------------------------------
IN = {}
l0.<java.lang.Throwable: java.lang.Throwable cause> = l0
OUT = {}
---------------------------------------
IN = {}
$stack1 = <java.lang.Throwable: java.lang.StackTraceElement[] UNASSIGNED_STACK>
OUT = {}
---------------------------------------
IN = {}
l0.<java.lang.Throwable: java.lang.StackTraceElement[] stackTrace> = $stack1
OUT = {}
---------------------------------------
IN = {}
$stack2 = <java.lang.Throwable: java.util.List SUPPRESSED_SENTINEL>
OUT = {}
---------------------------------------
IN = {}
l0.<java.lang.Throwable: java.util.List suppressedExceptions> = $stack2
OUT = {}
---------------------------------------
IN = {}
virtualinvoke l0.<java.lang.Throwable: java.lang.Throwable fillInStackTrace()>()
[NEW] X20 -> X21 <java.lang.Throwable: java.lang.Throwable fillInStackTrace()> 
ENTRY(X21) = {}
OUT = {}
---------------------------------------
IN = {}
l0 := @this: java.lang.Throwable
OUT = {}
---------------------------------------
IN = {}
$stack1 = l0.<java.lang.Throwable: java.lang.StackTraceElement[] stackTrace>
OUT = {}
---------------------------------------
IN = {}
if $stack1 != null goto specialinvoke l0.<java.lang.Throwable: java.lang.Throwable fillInStackTrace(int)>(0)
OUT = {}
---------------------------------------
IN = {}
$stack4 = l0.<java.lang.Throwable: java.lang.Object backtrace>
OUT = {}
---------------------------------------
IN = {}
if $stack4 == null goto return l0
OUT = {}
---------------------------------------
IN = {}
specialinvoke l0.<java.lang.Throwable: java.lang.Throwable fillInStackTrace(int)>(0)

Following is stack traces of the bug.

Stack trace:

java.lang.RuntimeException: no active body present for method <java.lang.Throwable: java.lang.Throwable fillInStackTrace(int)>
  at soot.SootMethod.getActiveBody(SootMethod.java:337)
  at vasco.soot.examples.SignAnalysis.callEntryFlowFunction(SignAnalysis.java:181)
  at vasco.soot.examples.SignAnalysis.callEntryFlowFunction(SignAnalysis.java:68)
  at vasco.ForwardInterProceduralAnalysis.doAnalysis(ForwardInterProceduralAnalysis.java:121)
  at vasco.soot.examples.SignTest.internalTransform(SignTest.java:45)
  at soot.SceneTransformer.transform(SceneTransformer.java:36)
  at soot.Transform.apply(Transform.java:102)
  at soot.ScenePack.internalApply(ScenePack.java:35)
  at soot.Pack.apply(Pack.java:117)
  at soot.PackManager.runWholeProgramPacks(PackManager.java:612)
  at soot.PackManager.runPacksNormally(PackManager.java:495)
  at soot.PackManager.runPacks(PackManager.java:419)
  at soot.Main.run(Main.java:269)
  at soot.Main.main(Main.java:141)
  at vasco.soot.examples.SignTest.main(SignTest.java:124)

But when I perform SignTest with the same commands and .jar in simple code like foo(within 100 lines of code), SignTest performed well. So I guess my error is related to too large space of Interprocedural relations in code. Can someone give me some advice?

Thanks

kimgimkigi commented 3 years ago

My error is similar to https://github.com/rohanpadhye/vasco/issues/14#issuecomment-555922901. Only 'SignAnalysis.java' and 'CopyConstantAnalysis.java' are different. But It goes to another error after fixing SignAnalysis with '!calledMethod.hasActiveBody()' check and return copy(invalue).

specialinvoke l0.<java.lang.Throwable: java.lang.Throwable fillInStackTrace(int)>(0)
java.lang.RuntimeException: no active body present for method <java.lang.Throwable: java.lang.Throwable fillInStackTrace(int)>
    at soot.SootMethod.getActiveBody(SootMethod.java:337)
    at vasco.soot.DefaultJimpleRepresentation.getControlFlowGraph(DefaultJimpleRepresentation.java:72)
    at vasco.soot.DefaultJimpleRepresentation.getControlFlowGraph(DefaultJimpleRepresentation.java:47)
    at vasco.ForwardInterProceduralAnalysis.initContext(ForwardInterProceduralAnalysis.java:293)
    at vasco.ForwardInterProceduralAnalysis.doAnalysis(ForwardInterProceduralAnalysis.java:129)
    at vasco.soot.examples.SignTest.internalTransform(SignTest.java:46)
    at soot.SceneTransformer.transform(SceneTransformer.java:36)
    at soot.Transform.apply(Transform.java:102)
    at soot.ScenePack.internalApply(ScenePack.java:35)
    at soot.Pack.apply(Pack.java:117)
    at soot.PackManager.runWholeProgramPacks(PackManager.java:612)
    at soot.PackManager.runPacksNormally(PackManager.java:495)
    at soot.PackManager.runPacks(PackManager.java:419)
    at soot.Main.run(Main.java:269)
    at soot.Main.main(Main.java:141)
    at vasco.soot.examples.SignTest.main(SignTest.java:127)

getControlFlowGraph In "DefaultJimpleRepresentation.java", It also has method.getActiveBody(). But in this case, I have no idea how to fix this case..

rohanpadhye commented 3 years ago

This is a standard problem with native Java methods, as documented in the README. Basically, the method java.lang.Throwable.fillInStackTrace is not implemented in Java itself, but within the JVM. So, static analysis (e.g. sign analysis) cannot compute data-flow information within this method.

If you want to analyze programs that depend on native methods, you can extend the DefaultJimpleRepresentation class to provide a representation that handles methods without bodies. For example, you may want to replace the methods with a no-op body. Or maybe you want to write mocks for each native method separately. The solution will vary based on the analysis and how much unsoundness or imprecision you are willing to tolerate.