<html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8"><style>body { line-height: 1.5; }blockquote { margin-top: 0px; margin-bottom: 0px; margin-left: 0.5em; }body { font-size: 10.5pt; font-family: 'Microsoft YaHei UI'; color: rgb(0, 0, 0); line-height: 1.5; }</style></head><body>
<div><span></span>Hi Eric,</div><div><br></div><div>Thank you for your kind reminder and timely help. <span style="font-size: 10.5pt; line-height: 1.5; background-color: transparent;">It works now.</span></div><div><br></div><div>The critical code is as follows, and maybe someone else also needs it.</div><div><br></div><div><div>Scene.v().loadNecessaryClasses();</div><div>// Resolve dependencies</div><div>Scene.v().loadClassAndSupport("java.lang.Object");</div><div>Scene.v().loadClassAndSupport("java.lang.System");</div><div>// Declare 'public class Main'</div><div>SootClass sClass = new SootClass("com.beust.jcommander.Main", Modifier.PUBLIC);</div><div>// 'extends Object'</div><div>sClass.setSuperclass(Scene.v().getSootClass("java.lang.Object"));</div><div>Scene.v().addClass(sClass);</div><div>// insert main method</div><div>SootMethod method = new SootMethod("main",</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Arrays.asList(new Type[] {ArrayType.v(RefType.v("java.lang.String"), 1)}),</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>VoidType.v(), Modifier.PUBLIC | Modifier.STATIC);</div><div>sClass.addMethod(method);</div><div>{</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>JimpleBody body = Jimple.v().newBody(method);</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre"> </span>method.setActiveBody(body);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Chain units = body.getUnits();</div><div> // instanitate an object</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Local tmpRef<span style="font-size: 10.5pt; line-height: 1.5; background-color: transparent;"> = Jimple.v().newLocal("jCommander", RefType.v("com.beust.jcommander.JCommander"));</span></div><div><span class="Apple-tab-span" style="white-space:pre"> </span>body.getLocals().add(tmpRef);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Stmt s = Jimple.v().newAssignStmt (tmpRef, Jimple.v().newNewExpr(</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>RefType.v("com.beust.jcommander.JCommander")));</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>units.addFirst(s);</div><div> // call a method</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>{</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>SootMethod toCall = Scene.v().getMethod(</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>"<com.beust.jcommander.JCommander: void parseWithoutValidation(java.lang.String[])>");</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>units.add(Jimple.v().newInvokeStmt(Jimple.v().newVirtualInvokeExpr(</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>tmpRef, toCall.makeRef(), StringConstant.v("Hello world!"))));</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>units.add(Jimple.v().newInvokeStmt(Jimple.v().newVirtualInvokeExpr(</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>tmpRef, toCall.makeRef())));</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>units.add(Jimple.v().newReturnVoidStmt());</div><div>}</div><div>//custom entry point</div><div>SootClass c = Scene.v().forceResolve("com.beust.jcommander.Main", SootClass.BODIES);</div><div>c.setApplicationClass();</div><div>List entryPoints = new ArrayList();</div><div>entryPoints.add(method);</div><div>Scene.v().setEntryPoints(entryPoints);</div></div><div><br></div><div>Best regards,</div><div>Yuan</div>
<blockquote style="margin-Top: 0px; margin-Bottom: 0px; margin-Left: 0.5em"><div> </div><div style="border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0cm 0cm 0cm"><div style="PADDING-RIGHT: 8px; PADDING-LEFT: 8px; FONT-SIZE: 12px;FONT-FAMILY:tahoma;COLOR:#000000; BACKGROUND: #efefef; PADDING-BOTTOM: 8px; PADDING-TOP: 8px"><div><b>From:</b> <a href="mailto:eric.bodden@uni-paderborn.de">Eric Bodden</a></div><div><b>Date:</b> 2020-06-22 07:17</div><div><b>To:</b> <a href="mailto:liuyuan@fastmail.com">liuyuan@fastmail.com</a></div><div><b>CC:</b> <a href="mailto:soot-list@CS.McGill.CA">soot-list</a></div><div><b>Subject:</b> Re: [Soot-list] Why Spark can't obtain the call graph on this snippet? But CHA can work.</div></div></div><div><div>Hi again.</div>
<div> </div>
<div>Your new main method also needs to instantiate the jCommander object, i.e.. call a constructor. Currently the reference is null!</div>
<div> </div>
<div>Cheers</div>
<div>Eric</div>
<div> </div>
<div>> On 19. Jun 2020, at 18:32, liuyuan@fastmail.com wrote:</div>
<div>> </div>
<div>> Hi Eric,</div>
<div>> </div>
<div>> Thank you for your prompt reply. </div>
<div>> </div>
<div>> According to you, I created a class (i.e., com.beust.jcommander.Main) and inserted a main method which calls the parseWithoutValidation method. But the call graph is also enpty. Could you help me with it?</div>
<div>> </div>
<div>> The code is as follows:</div>
<div>> Scene.v().loadNecessaryClasses();</div>
<div>> // creat the Main class</div>
<div>> Scene.v().loadClassAndSupport("java.lang.Object");</div>
<div>> Scene.v().loadClassAndSupport("java.lang.System");</div>
<div>> SootClass sClass = new SootClass("com.beust.jcommander.Main", Modifier.PUBLIC);</div>
<div>> sClass.setSuperclass(Scene.v().getSootClass("java.lang.Object"));</div>
<div>> Scene.v().addClass(sClass);</div>
<div>> // insert a main method</div>
<div>> SootMethod method = new SootMethod("main",</div>
<div>> Arrays.asList(new Type[] {ArrayType.v(RefType.v("java.lang.String"), 1)}),</div>
<div>> VoidType.v(), Modifier.PUBLIC | Modifier.STATIC);</div>
<div>> sClass.addMethod(method);</div>
<div>> {</div>
<div>> JimpleBody body = Jimple.v().newBody(method);</div>
<div>> </div>
<div>> method.setActiveBody(body);</div>
<div>> Chain units = body.getUnits();</div>
<div>> Local tmpRef;</div>
<div>> tmpRef = Jimple.v().newLocal("jCommander", RefType.v("com.beust.jcommander.JCommander"));</div>
<div>> body.getLocals().add(tmpRef);</div>
<div>> {</div>
<div>> SootMethod toCall = Scene.v().getMethod("<com.beust.jcommander.JCommander: void parseWithoutValidation(java.lang.String[])>");</div>
<div>> units.add(Jimple.v().newInvokeStmt(Jimple.v().newVirtualInvokeExpr(tmpRef, toCall.makeRef(), StringConstant.v("Hello world!"))));</div>
<div>> }</div>
<div>> units.add(Jimple.v().newReturnVoidStmt());</div>
<div>> }</div>
<div>> //custom entry point</div>
<div>> SootClass c = Scene.v().forceResolve("com.beust.jcommander.Main", SootClass.BODIES);</div>
<div>> c.setApplicationClass();</div>
<div>> List entryPoints = new ArrayList();</div>
<div>> entryPoints.add(method);</div>
<div>> Scene.v().setEntryPoints(entryPoints);</div>
<div>> </div>
<div>> </div>
<div>> I print the main method:</div>
<div>> public static void main(java.lang.String[])</div>
<div>> {</div>
<div>> com.beust.jcommander.JCommander jCommander;</div>
<div>> </div>
<div>> virtualinvoke jCommander.<com.beust.jcommander.JCommander: void parseWithoutValidation(java.lang.String[])>("Hello world!");</div>
<div>> </div>
<div>> return;</div>
<div>> }</div>
<div>> </div>
<div>> </div>
<div>> The parseWithoutValidationis as follows:</div>
<div>> /**</div>
<div>> * Parse the command line parameters without validating them.</div>
<div>> */</div>
<div>> public void parseWithoutValidation(String... args) {</div>
<div>> parse(false /* no validation */, args);</div>
<div>> }</div>
<div>> </div>
<div>> </div>
<div>> Best regards,</div>
<div>> Yuan</div>
<div>> From: Eric Bodden</div>
<div>> Date: 2020-06-19 04:07</div>
<div>> To: liuyuan@fastmail.com</div>
<div>> CC: soot-list</div>
<div>> Subject: Re: [Soot-list] Why Spark can't obtain the call graph on this snippet? But CHA can work.</div>
<div>> Hi Yuan.</div>
<div>> </div>
<div>> I am afraid things are not that simple. The problem is likely the following: Soot will use the method you configured as entry point, but thus is a non-static instance method, which calls other instance methods on “this”. That “this”-object however, has never been initialized by your entry point, thus Spark assumes it to be null - leading to an empty call graph.</div>
<div>> </div>
<div>> Thus, what we and many others have done in the past is the following: manually create a static mock-up method that properly initializes the object in question (and required helper objects) and then calls parseWithoutValidation. As entry point you then choose this new static mock-up method.</div>
<div>> </div>
<div>> Sometimes it may make sense to generate such methods automatically. FlowDroid, for instance, does this for Android apps.</div>
<div>> </div>
<div>> Cheers</div>
<div>> Eric</div>
<div>> </div>
<div>> > On 19. Jun 2020, at 00:16, liuyuan@fastmail.com wrote:</div>
<div>> > </div>
<div>> > Hi all,</div>
<div>> > </div>
<div>> > I customizd an entry point for a library (i.e. JCommander, a command interface tool for java) and used the Spark to build its CG. But The callgraph is empty. If I use the CHA, it works. </div>
<div>> > </div>
<div>> > The code snippet is as follows and the parseWithoutValidation is selected as the entry point.</div>
<div>> > public void parseWithoutValidation(String... args) { // the customized entry point</div>
<div>> > parse(false /* no validation */, args); // I think this method could be found easily by Spark~</div>
<div>> > }</div>
<div>> > </div>
<div>> > private void parse(boolean validate, String... args) {</div>
<div>> > StringBuilder sb = new StringBuilder("Parsing \"");</div>
<div>> > sb.append(join(args).append("\"\n with:").append(join(objects.toArray())));</div>
<div>> > p(sb.toString());</div>
<div>> > </div>
<div>> > if (descriptions == null) createDescriptions();</div>
<div>> > initializeDefaultValues();</div>
<div>> > parseValues(expandArgs(args), validate);</div>
<div>> > if (validate) validateOptions();</div>
<div>> > }</div>
<div>> > </div>
<div>> > private StringBuilder join(Object[] args) {</div>
<div>> > StringBuilder result = new StringBuilder();</div>
<div>> > for (int i = 0; i < args.length; i++) {</div>
<div>> > if (i > 0) result.append(" ");</div>
<div>> > result.append(args[i]);</div>
<div>> > }</div>
<div>> > return result;</div>
<div>> > }</div>
<div>> > ...</div>
<div>> > </div>
<div>> > My core code is as follows.</div>
<div>> > Options.v().set_process_dir(Arrays.asList(classesDir));</div>
<div>> > Options.v().set_whole_program(true);</div>
<div>> > Options.v().set_no_bodies_for_excluded(true);</div>
<div>> > Options.v().set_allow_phantom_refs(true);</div>
<div>> > </div>
<div>> > // set an entry point</div>
<div>> > SootClass c = Scene.v().forceResolve(entryClass, SootClass.BODIES);</div>
<div>> > c.setApplicationClass();</div>
<div>> > Scene.v().loadNecessaryClasses();</div>
<div>> > SootMethod method = c.getMethodByName(entryMethod);</div>
<div>> > List entryPoints = new ArrayList();</div>
<div>> > entryPoints.add(method);</div>
<div>> > Scene.v().setEntryPoints(entryPoints);</div>
<div>> > </div>
<div>> > //set Spark </div>
<div>> > HashMap<String, String> opt = new HashMap<String, String>();</div>
<div>> > opt.put("on-fly-cg", "true");</div>
<div>> > SparkTransformer.v().transform("", opt);</div>
<div>> > PhaseOptions.v().setPhaseOption("cg.spark", "enabled:true");</div>
<div>> > </div>
<div>> > PackManager.v().runPacks();</div>
<div>> > </div>
<div>> > The target java file is attached.</div>
<div>> > </div>
<div>> > Any suggestions are welcome.</div>
<div>> > </div>
<div>> > Best regards,</div>
<div>> > Yuan</div>
<div>> > <JCommander.java>_______________________________________________</div>
<div>> > Soot-list mailing list</div>
<div>> > Soot-list@CS.McGill.CA</div>
<div>> > https://mailman.CS.McGill.CA/mailman/listinfo/soot-list</div>
<div>> </div>
<div> </div>
</div></blockquote>
</body></html>