Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /* Soot - a J*va Optimization Framework
   * Copyright (C) 2003 Ondrej Lhotak
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
 
 package soot.jimple.toolkits.callgraph;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import soot.ArrayType;
 import soot.Body;
 import soot.Context;
 import soot.G;
 import soot.Kind;
 import soot.Local;
 import soot.RefType;
 import soot.Scene;
 import soot.SootClass;
 import soot.Transform;
 import soot.Type;
 import soot.Unit;
 import soot.Value;
Models the call graph.

Author(s):
Ondrej Lhotak
 
 public final class OnFlyCallGraphBuilder
 { 
 	public class DefaultReflectionModel implements ReflectionModel {
 		
 	    protected CGOptions options = new CGOptions( PhaseOptions.v().getPhaseOptions("cg") );
 	    
 	    protected HashSet<SootMethodwarnedAlready = new HashSet<SootMethod>();
 
 		public void classForName(SootMethod sourceStmt s) {
 	        List<LocalstringConstants = (List<Local>) .get(source);
 	        ifstringConstants == null )
	            .put(sourcestringConstants = new ArrayList<Local>());
	        Value className = ie.getArg(0);
	        ifclassName instanceof StringConstant ) {
	            String cls = ((StringConstantclassName ).;
	            constantForNameclssources );
	        } else {
	            Local constant = (LocalclassName;
	            if.safe_forname() ) {
	                for (SootMethod tgt : EntryPoints.v().clinits()) {
	                    addEdgesourcestgt. );
	                }
	            } else {
	                for (SootClass cls : Scene.v().dynamicClasses()) {
	                    for (SootMethod clinit : EntryPoints.v().clinitsOf(cls)) {
	                        addEdgesourcesclinit.);
	                    }
	                }
	                VirtualCallSite site = new VirtualCallSitessourcenullnull. );
	                List<VirtualCallSitesites = (List<VirtualCallSite>) .get(constant);
	                if (sites == null) {
	                    .put(constantsites = new ArrayList<VirtualCallSite>());
	                    stringConstants.add(constant);
	                }
	                sites.add(site);
	            }
	        }        
		}
		public void classNewInstance(SootMethod sourceStmt s) {
				for (SootMethod tgt : EntryPoints.v().inits()) {
					addEdgesourcestgt. );
				}
else {
				for (SootClass cls : Scene.v().dynamicClasses()) {
					ifcls.declaresMethod() ) {
						addEdgesourcescls.getMethod(), . );
					}
				}
				if.verbose() ) {
					G.v()..println"Warning: Method "+source+
							" is reachable, and calls Class.newInstance;"+
							" graph will be incomplete!"+
					" Use safe-newinstance option for a conservative result." );
				}
		}
		public void contructorNewInstance(SootMethod sourceStmt s) {
				for (SootMethod tgt : EntryPoints.v().allInits()) {
					addEdgesourcestgt. );
				}
else {
				for (SootClass cls : Scene.v().dynamicClasses()) {
					for(SootMethod mcls.getMethods()) {
						if(m.getName().equals("<init>")) {
							addEdgesourcesm. );
						}
					}
				}
				if.verbose() ) {
					G.v()..println"Warning: Method "+source+
							" is reachable, and calls Constructor.newInstance;"+
							" graph will be incomplete!"+
					" Use safe-newinstance option for a conservative result." );
				}
		}
		public void methodInvoke(SootMethod containerStmt invokeStmt) {
			if( !warnedAlready(container) ) {
				if.verbose() ) {
					G.v()..println"Warning: call to "+
							"java.lang.reflect.Method: invoke() from "+container+
					"; graph will be incomplete!" );
				}
				markWarned(container);
			}
		}
		private void markWarned(SootMethod m) {
		}
		private boolean warnedAlready(SootMethod m) {
		}
	}
	public class TraceBasedReflectionModel implements ReflectionModel {
		class Guard {
			public Guard(SootMethod containerStmt stmtString message) {
				this. = container;
				this. = stmt;
				this. = message;
			}
			final Stmt stmt;
			final String message;
		}
		protected Set<Guardguards;
		private boolean registeredTransformation = false;
			 = new HashSet<Guard>();
			if(logFile==null) {
				throw new InternalError("Trace based refection model enabled but no trace file given!?");
else {
			}
		}

Adds an edge to all class initializers of all possible receivers of Class.forName() calls within source.
		public void classForName(SootMethod containerStmt forNameInvokeStmt) {
			Set<StringclassNames = .classForNameClassNames(container);
			if(classNames==null || classNames.isEmpty()) {
				registerGuard(containerforNameInvokeStmt"Class.forName() call site; Soot did not expect this site to be reached");
else {
				for (String clsName : classNames) {
		            constantForNameclsNamecontainerforNameInvokeStmt );
				}
			}
		}

Adds an edge to the constructor of the target class from this call to java.lang.Class.newInstance().
		public void classNewInstance(SootMethod containerStmt newInstanceInvokeStmt) {
			if(classNames==null || classNames.isEmpty()) {
				registerGuard(containernewInstanceInvokeStmt"Class.newInstance() call site; Soot did not expect this site to be reached");
else {
				for (String clsName : classNames) {
					SootClass cls = Scene.v().getSootClass(clsName);
					ifcls.declaresMethod() ) {
						SootMethod constructor = cls.getMethod();
						addEdgecontainernewInstanceInvokeStmtconstructor. );
					}
				}
			}
		}

Adds a special edge of kind soot.Kind.REFL_CONSTR_NEWINSTANCE to all possible target constructors of this call to java.lang.reflect.Constructor.newInstance(java.lang.Object[]). Those kinds of edges are treated specially in terms of how parameters are assigned, as parameters to the reflective call are passed into the argument array of java.lang.reflect.Constructor.newInstance(java.lang.Object[]).

See also:
PAG#addCallTarget(Edge )
		public void contructorNewInstance(SootMethod containerStmt newInstanceInvokeStmt) {
			Set<StringconstructorSignatures = .constructorNewInstanceSignatures(container);
			if(constructorSignatures==null || constructorSignatures.isEmpty()) {
				registerGuard(containernewInstanceInvokeStmt"Constructor.newInstance(..) call site; Soot did not expect this site to be reached");
else {
				for (String constructorSignature : constructorSignatures) {
					SootMethod constructor = Scene.v().getMethod(constructorSignature);
					addEdgecontainernewInstanceInvokeStmtconstructor. );
				}
			}
		}

Adds a special edge of kind soot.Kind.REFL_INVOKE to all possible target methods of this call to java.lang.reflect.Method.invoke(java.lang.Object,java.lang.Object[]). Those kinds of edges are treated specially in terms of how parameters are assigned, as parameters to the reflective call are passed into the argument array of java.lang.reflect.Method.invoke(java.lang.Object,java.lang.Object[]).

See also:
PAG#addCallTarget(Edge )
		public void methodInvoke(SootMethod containerStmt invokeStmt) {
			Set<StringmethodSignatures = .methodInvokeSignatures(container);
			if (methodSignatures == null || methodSignatures.isEmpty()) {
				registerGuard(containerinvokeStmt"Method.invoke(..) call site; Soot did not expect this site to be reached");
else {
				for (String methodSignature : methodSignatures) {
					SootMethod method = Scene.v().getMethod(methodSignature);
					addEdgecontainerinvokeStmtmethod. );
				}
			}
		}
		private void registerGuard(SootMethod containerStmt stmtString string) {
			.add(new Guard(container,stmt,string));
				G.v()..println("Incomplete trace file: Class.forName() is called in method '" +
						container+"' but trace contains no information about the receiver class of this call.");
				if(.guards().equals("ignore")) {
					G.v()..println("Guarding strategy is set to 'ignore'. Will ignore this problem.");
else if(.guards().equals("print")) {
					G.v()..println("Guarding strategy is set to 'print'. " +
							"Program will print a stack trace if this location is reached during execution.");
else if(.guards().equals("throw")) {
					G.v()..println("Guarding strategy is set to 'throw'. Program will throw an " +
							"Error if this location is reached during execution.");
else {
					throw new RuntimeException("Invalid value for phase option (guarding): "+.guards());
				}
			}
				PackManager.v().getPack("wjap").add(new Transform("wjap.guards",new SceneTransformer() {
					protected void internalTransform(String phaseNameMap options) {
						for (Guard g : ) {
						}
					}
				}));
				PhaseOptions.v().setPhaseOption("wjap.guards""enabled");
			}
		}
		private void insertGuard(Guard guard) {
			if(.guards().equals("ignore")) return;
			SootMethod container = guard.container;
			Stmt insertionPoint = guard.stmt;
			if(!container.hasActiveBody()) {
				G.v()..println("WARNING: Tried to insert guard into "+container+" but couldn't because method has no body.");
else {
				Body body = container.getActiveBody();
				//exc = new Error
				RefType runtimeExceptionType = RefType.v("java.lang.Error");
				NewExpr newExpr = Jimple.v().newNewExpr(runtimeExceptionType);
				LocalGenerator lg = new LocalGenerator(body);
				Local exceptionLocal = lg.generateLocal(runtimeExceptionType);
				AssignStmt assignStmt = Jimple.v().newAssignStmt(exceptionLocalnewExpr);
				body.getUnits().insertBefore(assignStmtinsertionPoint);
				//exc.<init>(message)
				SootMethodRef cref = runtimeExceptionType.getSootClass().getMethod("<init>", Collections.singletonList(RefType.v("java.lang.String"))).makeRef();
				SpecialInvokeExpr constructorInvokeExpr = Jimple.v().newSpecialInvokeExpr(exceptionLocalcref, StringConstant.v(guard.message));
				InvokeStmt initStmt = Jimple.v().newInvokeStmt(constructorInvokeExpr);
				body.getUnits().insertAfter(initStmtassignStmt);
				if(.guards().equals("print")) {
					//exc.printStackTrace();
					VirtualInvokeExpr printStackTraceExpr = Jimple.v().newVirtualInvokeExpr(exceptionLocal, Scene.v().getSootClass("java.lang.Throwable").getMethod("printStackTrace", Collections.emptyList()).makeRef());
					InvokeStmt printStackTraceStmt = Jimple.v().newInvokeStmt(printStackTraceExpr);
					body.getUnits().insertAfter(printStackTraceStmtinitStmt);
else if(.guards().equals("throw")) {
					body.getUnits().insertAfter(Jimple.v().newThrowStmt(exceptionLocal), initStmt);
else {
					throw new RuntimeException("Invalid value for phase option (guarding): "+.guards());
				}
			}
		}
	}

    
context-insensitive stuff
    private final CallGraph cicg = new CallGraph();
    private final HashSet<SootMethodanalyzedMethods = new HashSet<SootMethod>();
    private final LargeNumberedMap receiverToSites = new LargeNumberedMap( Scene.v().getLocalNumberer() ); // Local -> List(VirtualCallSite)
    private final LargeNumberedMap methodToReceivers = new LargeNumberedMap( Scene.v().getMethodNumberer() ); // SootMethod -> List(Local)
    public LargeNumberedMap methodToReceivers() { return ; }
    private final SmallNumberedMap stringConstToSites = new SmallNumberedMap( Scene.v().getLocalNumberer() ); // Local -> List(VirtualCallSite)
    private final LargeNumberedMap methodToStringConstants = new LargeNumberedMap( Scene.v().getMethodNumberer() ); // SootMethod -> List(Local)
    private CGOptions options;
    private boolean appOnly;

    
context-sensitive stuff
    private ReachableMethods rm;
    private QueueReader worklist;
    private ContextManager cm;
    private final ChunkedQueue targetsQueue = new ChunkedQueue();
    private final QueueReader targets = .reader();
    public OnFlyCallGraphBuilderContextManager cmReachableMethods rm ) {
        this. = cm;
        this. = rm;
         = rm.listener();
         = new CGOptions( PhaseOptions.v().getPhaseOptions("cg") );
        if( !.verbose() ) {
            G.v()..println"[Call Graph] For information on where the call graph may be incomplete, use the verbose option to the cg phase." );
        }
        
//        if(options.reflection_log()==null || options.reflection_log().length()==0) {
        	 = new DefaultReflectionModel();
//        } else {
//        	reflectionModel = new TraceBasedReflectionModel();
//        }
    }
    public OnFlyCallGraphBuilderContextManager cmReachableMethods rmboolean appOnly ) {
        thiscmrm );
        this. = appOnly;
    }
    public void processReachables() {
        while(true) {
            if( !.hasNext() ) {
                .update();
                if( !.hasNext() ) break;
            }
            MethodOrMethodContext momc = (MethodOrMethodContext.next();
            SootMethod m = momc.method();
            if && !m.getDeclaringClass().isApplicationClass() ) continue;
            if.addm ) ) processNewMethodm );
            processNewMethodContextmomc );
        }
    }
    public boolean wantTypesLocal receiver ) {
        return .get(receiver) != null;
    }
    public void addTypeLocal receiverContext srcContextType typeContext typeContext ) {
        FastHierarchy fh = Scene.v().getOrMakeFastHierarchy();
        forIterator siteIt = ((Collection.getreceiver )).iterator(); siteIt.hasNext(); ) {
            final VirtualCallSite site = (VirtualCallSitesiteIt.next();
            InstanceInvokeExpr iie = site.iie();
            ifsite.kind() == . 
            && !fh.canStoreTypetype ) )
                continue;
            ifsite.iie() instanceof SpecialInvokeExpr && site.kind != . ) {
            	SootMethod target = VirtualCalls.v().resolveSpecial
                            (SpecialInvokeExprsite.iie(),
                            site.subSig(),
                            site.container() );
            	//if the call target resides in a phantom class then "target" will be null;
            	//simply do not add the target in that case
            	if(target!=null) {
            		.addtarget );            		
            	} 
            } else {
                VirtualCalls.v().resolvetype,
                        receiver.getType(),
                        site.subSig(),
                        site.container(), 
                         );
            }
            while(.hasNext()) {
                SootMethod target = (SootMethod.next();
                .addVirtualEdge(
                        MethodContext.vsite.container(), srcContext ),
                        site.stmt(),
                        target,
                        site.kind(),
                        typeContext );
            }
        }
    }
    public boolean wantStringConstantsLocal stringConst ) {
        return .get(stringConst) != null;
    }
    public void addStringConstantLocal lContext srcContextString constant ) {
        forIterator siteIt = ((Collection.getl )).iterator(); siteIt.hasNext(); ) {
            final VirtualCallSite site = (VirtualCallSitesiteIt.next();
            ifconstant == null ) {
                if.verbose() ) {
                    G.v()..println"Warning: Method "+site.container()+
                        " is reachable, and calls Class.forName on a"+
                        " non-constant String; graph will be incomplete!"+
                        " Use safe-forname option for a conservative result." );
                }
            } else {
                ifconstant.length() > 0 && constant.charAt(0) == '[' ) {
                    ifconstant.length() > 1 && constant.charAt(1) == 'L' 
                    && constant.charAt(constant.length()-1) == ';' ) {
                        constant = constant.substring(2,constant.length()-1);
                    } else continue;
                }
                if( !Scene.v().containsClassconstant ) ) {
                    if.verbose() ) {
                        G.v()..println"Warning: Class "+constant+" is"+
                            " a dynamic class, and you did not specify"+
                            " it as such; graph will be incomplete!" );
                    }
                } else {
                    SootClass sootcls = Scene.v().getSootClassconstant );
                    if( !sootcls.isApplicationClass() ) {
                        sootcls.setLibraryClass();
                    }
                    for (SootMethod clinit : EntryPoints.v().clinitsOf(sootcls)) {
                        .addStaticEdge(
                                MethodContext.vsite.container(), srcContext ),
                                site.stmt(),
                                clinit,
                                . );
                    }
                }
            }
        }
    }
    /* End of public methods. */
    private void addVirtualCallSiteStmt sSootMethod mLocal receiver,
            InstanceInvokeExpr iieNumberedString subSigKind kind ) {
        List<VirtualCallSitesites = (List<VirtualCallSite>) .get(receiver);
        if (sites == null) {
            .put(receiversites = new ArrayList<VirtualCallSite>());
            List<Localreceivers = (List<Local>) .get(m);
            ifreceivers == null )
                .put(mreceivers = new ArrayList<Local>());
            receivers.add(receiver);
        }
        sites.add(new VirtualCallSite(smiiesubSigkind));
    }
    private void processNewMethodSootMethod m ) {
        ifm.isNative() || m.isPhantom() ) {
            return;
        }
        Body b = m.retrieveActiveBody();
        getImplicitTargetsm );
        findReceivers(mb);
    }
    private void findReceivers(SootMethod mBody b) {
        forIterator sIt = b.getUnits().iterator(); sIt.hasNext(); ) {
            final Stmt s = (StmtsIt.next();
            if (s.containsInvokeExpr()) {
                InvokeExpr ie = s.getInvokeExpr();
                if (ie instanceof InstanceInvokeExpr) {
                    InstanceInvokeExpr iie = (InstanceInvokeExprie;
                    Local receiver = (Localiie.getBase();
                    NumberedString subSig = 
                        iie.getMethodRef().getSubSignature();
                    addVirtualCallSitesmreceiveriiesubSig,
                            Edge.ieToKind(iie) );
                    ifsubSig ==  ) {
                        addVirtualCallSitesmreceiveriie,
                                . );
                    }
                } else {
                	SootMethod tgt = ie.getMethod();
                	addEdge(mstgt);
                	iftgt.getSignature().equals"<java.security.AccessController: java.lang.Object doPrivileged(java.security.PrivilegedAction)>" )
                			||  tgt.getSignature().equals"<java.security.AccessController: java.lang.Object doPrivileged(java.security.PrivilegedExceptionAction)>" )
                			||  tgt.getSignature().equals"<java.security.AccessController: java.lang.Object doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)>" )
                			||  tgt.getSignature().equals"<java.security.AccessController: java.lang.Object doPrivileged(java.security.PrivilegedExceptionAction,java.security.AccessControlContext)>" ) ) {
                		
                		Local receiver = (Localie.getArg(0);
                		addVirtualCallSitesmreceivernull,
                				. );
                	}                    	
                }
            }
        }
    }
    
    
    private void getImplicitTargetsSootMethod source ) {
        final SootClass scl = source.getDeclaringClass();
        ifsource.isNative() || source.isPhantom() ) return;
        ifsource.getSubSignature().indexOf"<init>" ) >= 0 ) {
            handleInit(sourcescl);
        }
        Body b = source.retrieveActiveBody();
        forIterator sIt = b.getUnits().iterator(); sIt.hasNext(); ) {
            final Stmt s = (StmtsIt.next();
            ifs.containsInvokeExpr() ) {
                InvokeExpr ie = s.getInvokeExpr();
                ifie.getMethodRef().getSignature().equals"<java.lang.reflect.Method: java.lang.Object invoke(java.lang.Object,java.lang.Object[])>" ) ) {
                	.methodInvoke(source,s);
                }
                ifie.getMethodRef().getSignature().equals"<java.lang.Class: java.lang.Object newInstance()>" ) ) {
                	.classNewInstance(source,s);
                }
                ifie.getMethodRef().getSignature().equals"<java.lang.reflect.Constructor: java.lang.Object newInstance(java.lang.Object[])>" ) ) {
                	.contructorNewInstance(sources);
                }
                ifie.getMethodRef().getSubSignature() ==  ) {
                	.classForName(source,s);
                }
                ifie instanceof StaticInvokeExpr ) {
                	SootClass cl = ie.getMethodRef().declaringClass();
                	for (SootMethod clinit : EntryPoints.v().clinitsOf(cl)) {
                		addEdgesourcesclinit. );
                	}
                }
            }
            ifs.containsFieldRef() ) {
                FieldRef fr = s.getFieldRef();
                iffr instanceof StaticFieldRef ) {
                    SootClass cl = fr.getFieldRef().declaringClass();
                    for (SootMethod clinit : EntryPoints.v().clinitsOf(cl)) {
                        addEdgesourcesclinit. );
                    }
                }
            }
            ifs instanceof AssignStmt ) {
                Value rhs = ((AssignStmt)s).getRightOp();
                ifrhs instanceof NewExpr ) {
                    NewExpr r = (NewExprrhs;
                    SootClass cl = r.getBaseType().getSootClass();
                    for (SootMethod clinit : EntryPoints.v().clinitsOf(cl)) {
                        addEdgesourcesclinit. );
                    }
                } else ifrhs instanceof NewArrayExpr || rhs instanceof NewMultiArrayExpr ) {
                    Type t = rhs.getType();
                    ift instanceof ArrayType ) t = ((ArrayType)t).;
                    ift instanceof RefType ) {
                        SootClass cl = ((RefTypet).getSootClass();
                        for (SootMethod clinit : EntryPoints.v().clinitsOf(cl)) {
                            addEdgesourcesclinit. );
                        }
                    }
                }
            }
        }
    }
    private void processNewMethodContextMethodOrMethodContext momc ) {
        SootMethod m = momc.method();
        Object ctxt = momc.context();
        Iterator it = .edgesOutOf(m);
        whileit.hasNext() ) {
            Edge e = (Edgeit.next();
            .addStaticEdgemomce.srcUnit(), e.tgt(), e.kind() );
        }
    }
    private void handleInit(SootMethod sourcefinal SootClass scl) {
        addEdgesourcenullscl. );
    }
    private void constantForNameString clsSootMethod srcStmt srcUnit ) {
        ifcls.length() > 0 && cls.charAt(0) == '[' ) {
            ifcls.length() > 1 && cls.charAt(1) == 'L' && cls.charAt(cls.length()-1) == ';' ) {
                cls = cls.substring(2,cls.length()-1);
                constantForNameclssrcsrcUnit );
            }
        } else {
            if( !Scene.v().containsClasscls ) ) {
                if.verbose() ) {
                    G.v()..println"Warning: Class "+cls+" is"+
                        " a dynamic class, and you did not specify"+
                        " it as such; graph will be incomplete!" );
                }
            } else {
                SootClass sootcls = Scene.v().getSootClasscls );
                if( !sootcls.isApplicationClass() ) {
                    sootcls.setLibraryClass();
                }
                for (SootMethod clinit : EntryPoints.v().clinitsOf(sootcls)) {
                    addEdgesrcsrcUnitclinit. );
                }
            }
        }
    }
    private void addEdgeSootMethod srcStmt stmtSootMethod tgt,
            Kind kind ) {
        .addEdgenew Edgesrcstmttgtkind ) );
    }
    private void addEdge(  SootMethod srcStmt stmtSootClass clsNumberedString methodSubSigKind kind ) {
        ifcls.declaresMethodmethodSubSig ) ) {
            addEdgesrcstmtcls.getMethodmethodSubSig ), kind );
        }
    }
    private void addEdgeSootMethod srcStmt stmtSootMethod tgt ) {
        InvokeExpr ie = stmt.getInvokeExpr();
        addEdgesrcstmttgt, Edge.ieToKind(ie) );
    }
    protected final NumberedString sigFinalize = Scene.v().getSubSigNumberer().
        findOrAdd"void finalize()" );
    protected final NumberedString sigInit = Scene.v().getSubSigNumberer().
        findOrAdd"void <init>()" );
    protected final NumberedString sigStart = Scene.v().getSubSigNumberer().
        findOrAdd"void start()" );
    protected final NumberedString sigRun = Scene.v().getSubSigNumberer().
        findOrAdd"void run()" );
    protected final NumberedString sigObjRun = Scene.v().getSubSigNumberer().
        findOrAdd"java.lang.Object run()" );
    protected final NumberedString sigForName = Scene.v().getSubSigNumberer().
        findOrAdd"java.lang.Class forName(java.lang.String)" );
    protected final RefType clRunnable = RefType.v("java.lang.Runnable");
    
New to GrepCode? Check out our FAQ X