Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Prerequisites • Install Scala IDE for Scala 2.11.2 from www.scala-ide.org • Install Scala 2.11.2 from www.scala-lang.org • Install SBT 0.13.6 from www.scala-sbt.org • Create a clone of the master branch of OPAL www.bitbucket.org/delors/opal • To test that everything works smoothly compile the project: • • • Test the project • sbt test • sbt it:test Create and then import the Eclipse projects • • sbt clean copyResources test:compile sbt eclipse Run again (sometimes some resources are forgotten and something won’t work (tools etc.)…) • sbt copyResources The OPAL Framework A Tutorial Michael Eichberg Oktober 2014 2 Architecture Abstract Interpretation Framework! Analyses that are concerned with a program’s control and data-flow (and which provides reasonable abstractions thereof) “resolved” Bytecode Representation! Object-oriented representation of Java class files Well suited for lightweight static analyses (e.g., to analyze an application’s static structure, to find instances of bug patterns.) Bytecode Infrastructure! Generic infrastructure for parsing Java class files. Abstract Interpretation Framework! Analyses that are concerned with a program’s control and data-flow (and which provides reasonable abstractions thereof) “resolved” Bytecode Representation! Lightweight static analyses (e.g., to analyze an application’s static structure, to find instances of bug patterns.) Bytecode Infrastructure! Low-level “analyses” directly on top the bytecode representation (e.g., to do bytecode verification, to create other representations of Java bytecode, to find instances of bug patterns (sequence of bytecode instructions).) The Bytecode Representation Part I The package: org.opalj.br • Classes used for the representation of Java class files. Basically, each major element of a class file (Method Declaration, Field Declaration, each “Attribute”,…) is represented using one class. (The code base and the JVM specification are well-aligned.) • By default all information is represented. (Except of the BootstrapMethodTable, which is resolved; the information is directly attached to the respective Invokedynamic instructions.) • Traversal of class files is primarily facilitated by Pattern Matching. (Signatures also support the traversal using a Visitor) The package: org.opalj.br • Main classes: • ClassFile (java.lang.Object is the superclass of all classes except of itself.) • • Method • MethodDescriptor (Parameter types and return type.) • Code (If the method is non-native and non-abstract.) The instructions array may contain “null” values. Defines many helper methods to facilitate the traversal of the instructions array. Field The package: org.opalj.br • Main classes: • Type Types can be compared using reference comparison (eq). All types are associated with a unique id. • ReferenceType • ObjectType The name uses the binary notation. Not java.lang.Object, but java/lang/Object) Common ObjectTypes are predefined. • ArrayType The package: org.opalj.br.instructions • Representation of a method’s instructions. The type hierarchy and many extractors facilitate the matching of byte code sequences/facilitate the abstraction over different types of byte code instructions. • Important Concepts • In Java Bytecode we have four(five) different instructions to invoke a method (Invokespecial, Invokestatic, Invokevirtual, Invokeinterface) • Creating a class is a two step process: • allocating the memory (using New) • invoking the constructor (using Invokespecial) Example - Matching Instructions The package: org.opalj.br.instructions val superClass : ObjectType = … for { method @ MethodWithBody(body) ← classFile.methods body.instructions.exists { case INVOKESPECIAL( `superClass`, "clone", MethodDescriptor(Seq(), ObjectType.Object)) case _ } } yield … false; true; The package: org.opalj.br.reader • • Classes to read in Java Class Files. Main classes: • Java8Framework Represents “all” information. (Attributes that are not supported are discarded.) • Java8LibraryFramework Only represents those information that describe the public interface. In most cases, however, it is more useful to load class files (implicitly) using a Project. Adhoc Analyses Prototyping Analyses Using the Scala REPL http://www.blackrocktools.com Tekton 3030, 16oz Wood Rip Hammer - 3030 The Scala REPL OPAL is easy to explore using Scala’s REPL OPAL facilitates prototyping (parts of) analyses using the REPL Get the number of abstract methods defined in the rt.jar pc-eichberg:OPAL eichberg$ sbt! Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=384m; support was removed in 8.0! [info] Loading project definition from /Users/eichberg/Code/OPAL/project! [info] Set current project to OPAL Library (in build file:/Users/eichberg/Code/OPAL/)! > project BytecodeRepresentation! [info] Set current project to Bytecode Representation (in build file:/Users/eichberg/Code/OPAL/)! > console! [info] Starting scala interpreter...! [info] ! Welcome to Scala version 2.11.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_05).! Type in expressions to have them evaluated.! Type :help for more information.! ! scala> import org.opalj.br.reader.Java8Framework._! import org.opalj.br.reader.Java8Framework._! ! val cfs = ClassFiles(new java.io.File("/Library/Java/JavaVirtualMachines/ jdk1.8.0_05.jdk/Contents/Home/jre/lib/rt.jar"))! scala> cfs: Seq[(org.opalj.br.reader.Java8Framework.ClassFile, java.net.URL)] =! List((ClassFile(! ! public [SUPER] java.lang.SecurityManager! ! extends java.lang.Object! ! {version=52.0}! ),jar:file:/Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/jre/lib/rt.jar!/java/lang/ Short$ShortCache.class), (ClassFile(! ! [SUPER] java.lang.Shut...! scala> cfs.size! res0: Int = 20526! scala> cfs.map(cf => cf._1.methods.filter(_.isAbstract).size).sum! res3: Int = 16793! ! scala> :q! Leave the console and return to sbt. Exercise • Get the number of abstract methods defined in abstract classes (not interfaces). • Help: • www.opal-project.de/library/api/SNAPSHOT • www.scala-lang.org/api/2.11.2 scala> import org.opalj.br.reader.Java8Framework._! import org.opalj.br.reader.Java8Framework._! ! val cfs = ClassFiles(new java.io.File(“/Library/Java/ JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/jre/lib/rt.jar"))! scala> ! cfs.filter(cf => !cf._1.isInterfaceDeclaration).map(cf => cf._1.methods.filter(_.isAbstract).size).sum! scala> Solution res3: Int = 4587 The package: org.opalj.br.analyses • Commonly useful analyses or classes that support the development of analyses. • Project Primary abstraction of a Java Project. Serves as a container for global information (e.g. the call graph, the class hierarchy). Enables the navigation from Methods, Fields and ObjectTypes to ClassFiles. • ClassHierarchy Representation of the class hierarchy. Support methods to calculate least upper type bounds and to resolve method and field references. Supports partial class hierarchies. • AnalysisExecutor Template class that facilitates the development of new analyses. Get all classes that extend java.util.AbstractList (including anonymous classes.) > console! [info] Starting scala interpreter...! [info] ! Welcome to Scala version 2.11.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_05).! Type in expressions to have them evaluated.! Type :help for more information.! ! val p = org.opalj.br.analyses.Project(new java.io.File("/Library/Java/ JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/jre/lib/rt.jar"))! scala> p: org.opalj.br.analyses.Project[java.net.URL] =! Project(! ! java.awt.geom.Rectangle2D « jar:file:/Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/ Home/jre/lib/rt.jar!/java/awt/geom/Rectangle2...! scala> p.classHierarchy.allSubtypes(org.opalj.br.ObjectType("java/util/ AbstractList"),false).filter(_.packageName.startsWith("java/")).mkString("\n")! res0: String =! ObjectType(java/util/Collections$EmptyList)! ObjectType(java/util/RandomAccessSubList)! ObjectType(java/util/ArrayList)! ObjectType(java/util/concurrent/CopyOnWriteArrayList$COWSubList)! ObjectType(java/util/LinkedList)! ObjectType(java/util/Vector)! ObjectType(java/util/SubList)! ObjectType(java/util/ArrayList$SubList)! ObjectType(java/util/Stack)! ObjectType(java/util/AbstractSequentialList)! ObjectType(java/util/Collections$CopiesList)! ObjectType(java/util/Collections$SingletonList)! ObjectType(java/util/Arrays$ArrayList)! ! scala> AnalysisExecutor The package: org.opalj.br.analyses package org.opalj.ai.tutorial.base ! import import import import import java.net.URL org.opalj._ org.opalj.br._ org.opalj.br.analyses._ org.opalj.ai._ ! object AnalysisTemplate extends AnalysisExecutor { ! val analysis = new OneStepAnalysis[URL, BasicReport] { ! override def doAnalyze( theProject: Project[URL], parameters: Seq[String], isInterrupted: () Boolean) = { // HERE GOES YOUR ANALYSIS BasicReport(theProject.statistics.mkString("\n")) } } } The Bytecode Representation • General Design Decisions • All classes are (effectively) immutable. (Supports parallelization.) • Extensive support for pattern matching. If available, always use the accessor methods offered by the class that manages the collection and not the collection itself. E.g., to find a method with a specific name, use the respective method defined by Method and do not use the collection’s find method. • No “null” values. (There is only one exception: the instructions array) Example - clone method calls super.clone() The Bytecode Representation for { classFile ← classFiles if !classFile.isInterfaceDeclaration && !classFile.isAnnotationDeclaration superClass ← classFile.superclassType.toList method @ Method(_, "clone", MethodDescriptor(Seq(), ObjectType.Object)) ← classFile.methods if !method.isAbstract if !method.body.get.instructions.exists { case INVOKESPECIAL( `superClass`, "clone", MethodDescriptor(Seq(), ObjectType.Object)) true; case _ false; } } yield (classFile /*.thisClass.className*/ , method /*.name*/ ) Exercise • Develop an analysis that collects all constructor calls in all methods that create an instance of java.io.File using the constructor (File(String s)). • The analysis should return a triple of type: ( /*Declaring Class*/ ClassFile, /*Caller*/ Method, /*PCs of constructor calls*/ Set[PC]) I.e., for each method the set of program counters that call the respective constructor should be returned. • Execute the analysis in parallel. import import import import import import ! java.net.URL org.opalj._ org.opalj.br._ org.opalj.br.analyses._ org.opalj.br.instructions._ org.opalj.ai._ object IdentifyResourcesAnalysis extends AnalysisExecutor { ! ! val analysis = new OneStepAnalysis[URL, BasicReport] { override def title: String = "File Object Creation Using Constant Strings" ! override def description: String = "Identifies java.io.File object instantiations using constant strings." ! override def doAnalyze(theProject: Project[URL], parameters: Seq[String], isInterrupted: () Boolean) = { Solution val callSites = (for { cf ← theProject.classFiles.par m @ MethodWithBody(body) ← cf.methods } yield { val pcs = for { pc ← body.collectWithIndex { case ( pc, INVOKESPECIAL( ObjectType("java/io/File"), "<init>", SingleArgumentMethodDescriptor((ObjectType.String, VoidType))) ) pc } } yield pc (cf, m, pcs) }).filter(_._3.size > 0) BasicReport(…) } } } Abstract Interpretation Framework! Analyses that are concerned with a program’s control and data-flow (and which provides reasonable abstractions thereof) “resolved” Bytecode Representation! Lightweight static analyses (e.g., to analyze an application’s static structure, to find instances of bug patterns.) Bytecode Infrastructure! Low-level “analyses” directly on top the bytecode representation (e.g., to do bytecode verification, to create other representations of Java bytecode, to find instances of bug patterns (sequence of bytecode instructions).) The Abstract Interpretation Framework Part II The Abstract Interpretation Framework • Static analysis framework that is inspired by Model Checking/ Symbolic Execution and Abstract Interpretation • Works directly on top of Java bytecode to reduce overhead (I.e., OPAL does not use an intermediate representation, such as SSA.) • Complexity of Java bytecode is completely hidden within OPAL • "Functional Style" to facilitate parallelization/to avoid hard to find bugs (most objects cannot be mutated and those that can be mutated are not expected to be mutated) • User defined precision (no framework inherent limitations) An analysis that reports all return instructions of all methods that return an integer value where the return value is bounded. public void myMethod(int i) { if (i < 0) return -1; // <= bounded; should be returned. else return i; // <= unbounded } ! It basically (re)uses the predefined abstract domains. ! The analysis does not consider calls to further methods. Identifying ireturn instructions that return bounded integer values. > console! import import import import import import ! org.opalj._! org.opalj.br._! org.opalj.br.analyses._! org.opalj.ai._! org.opalj.ai.domain._! org.opalj.ai.domain.l1._! val p = Project(new java.io.File("/Library/Java/JavaVirtualMachines/ jdk1.8.0_05.jdk/Contents/Home/jre/lib/rt.jar"))! ! val methods = p.methods.filter(m => m.body.isDefined && m.descriptor.returnType == IntegerType)! ! class TheDomain(p:Project[java.net.URL],cf : ClassFile,m : Method) extends DefaultDomain(p,cf,m) with RecordLastReturnedValues! ! methods.foreach{m => ! val cf = p.classFile(m)! val r = BaseAI(cf,m,new TheDomain(p,p.classFile(m),m)).domain! == 1)! r.allReturnedValues.foreach(_ if(r.allReturnedValues.size match {! (if you want to get all methods with a single return instruction) case (pc,r.IntegerRange(x,y)) => ! println(cf.thisType.toJava+"{ "+m.toJava+"; pc="+pc+":["+x+","+y+"]"+" }")! case _ => /***/! })! } sun.awt.image.ImagingLib{ int getNativeOpIndex(java.lang.Class); pc=30:[-1,2] } Identifying ireturn instructions that return bounded integer values. > console! org.opalj._! org.opalj.br._! 137 private static int getNativeOpIndex(Class opClass) { org.opalj.br.analyses._! 138 // org.opalj.ai._! 139 // Search for this class in cached list of org.opalj.ai.domain._! 140 // classes supplying native acceleration org.opalj.ai.domain.l1._! 141 // ! 142 int opIndex = -1; val p = Project(new java.io.File("/Library/Java/JavaVirtualMachines/ 143 for (int i=0; i<NUM_NATIVE_OPS; i++) { jdk1.8.0_05.jdk/Contents/Home/jre/lib/rt.jar"))! 144 if (opClass == nativeOpClass[i]) { ! 145 opIndex = i; val methods = p.methods.filter(m => m.body.isDefined && m.descriptor.returnType == 146 break; IntegerType)! 147 } ! 148 } class TheDomain(p:Project[java.net.URL],cf : ClassFile,m : Method) extends DefaultDomain(p,cf,m) with RecordLastReturnedValues! 149 return opIndex; ! 150 } methods.foreach{m => ! val cf = p.classFile(m)! val r = BaseAI(cf,m,new TheDomain(p,p.classFile(m),m)).domain! r.allReturnedValues.foreach(_ match {! case (pc,r.IntegerRange(x,y)) => ! println(cf.thisType.toJava+"{ "+m.toJava+"; pc="+pc+":["+x+","+y+"]"+" }")! case _ => /***/! })! } this constant is “3” jd k 1. 8. 0_ 05 import import import import import import sun.awt.image.ImagingLib{ int getNativeOpIndex(java.lang.Class); pc=30:[-1,2] } Identifying areturn instructions that return null values. > console! import import import import import import ! org.opalj._! org.opalj.br._! org.opalj.br.analyses._! org.opalj.ai._! org.opalj.ai.domain._! org.opalj.ai.domain.l1._! val p = Project(new java.io.File("/Library/Java/JavaVirtualMachines/ jdk1.8.0_05.jdk/Contents/Home/jre/lib/rt.jar"))! ! val methods = p.methods.filter(m => m.body.isDefined && m.descriptor.returnType.isObjectType)! ! class TheDomain(p:Project[java.net.URL],cf : ClassFile,m : Method) extends DefaultDomain(p,cf,m) with RecordLastReturnedValues! ! methods.foreach{m => ! val cf = p.classFile(m)! val r = BaseAI(cf,m,new TheDomain(p,p.classFile(m),m)).domain! r.allReturnedValues.foreach(_ match {! case (pc,r.NullValue()) => ! println(cf.thisType.toJava+"{ "+m.toJava+"; pc="+pc)! case _ => /***/! })! } Understanding Available Domains OPAL comes with several tools that facilitate the development of analyses using the abstract interpretation framework. http://www.blackrocktools.com Tekton 3030, 16oz Wood Rip Hammer - 3030 Understanding the result of an abstract interpretation of a method. static void cfDependentValues4() { int b = 0; int c = 0; int i = 0; int j = i; // j is just an alias for i while (j < 2) { int a = anInt(); if (i == 1) b = a; else c = a; i++; j = i; } if (i == 2) { doIt(j); // j == 2 doIt(b); // some value (but not "c") doIt(c); // some value (but not "b") } } The XHTML Tracer (0.1) an instruction where two or more paths join The XHTML Tracer (0.1) 10 1 3 2 9 5 4 6 8 7 The AI performs a strict depth-first evaluation. The XHTML Tracer (0.1) The AI performs a strict depth-first evaluation. Four Different Approaches to Develop Analyses Using the AI Framework can be Distinguished • by reusing a pre-configured Domain to pre-analyze the method and then analyzing the result • by configuring a Domain w.r.t. the analysis task at hand (By means of mixin-composition of existing partial domains.) • by adapting/configuring a Domain (By means of subclassing a Domain.) • by developing a new Domain Custom analysis are built by tailoring the “Domain”. The Abstract Interpretation Framework Domain The Analysis’ Domain Base Domains FieldAccessesDomain VMLevelExceptionsFactory DoubleValuesDomain DoubleValuesFactory CoreDomain FloatValuesDomain FloatValuesFactory LongValuesDomain LongValuesFactory IntegerValuesDomain IntegerValuesFactory PrimitiveValuesConversionsDomain JoinStabilization PrimitiveValuesFactory ReturnInstructionsDomain ReferenceValuesFactory TypedValuesFactory ReferenceValuesDomain MonitorInstructionsDomain MethodCallsDomain DefaultDomainValueBinding The Core Domains Domain Commonly Useful Helper Domains General Support ConcreteIntegerValues ConcreteLongValues Origin TheProject ProjectBasedClassHierarchy ClassHierarchy TheCode TheMethod Configuration Base Domains FieldAccessesDomain VMLevelExceptionsFactory DoubleValuesDomain DoubleValuesFactory CoreDomain FloatValuesDomain FloatValuesFactory LongValuesDomain LongValuesFactory IntegerValuesDomain IntegerValuesFactory PrimitiveValuesConversionsDomain JoinStabilization PrimitiveValuesFactory ReturnInstructionsDomain ReferenceValuesFactory TypedValuesFactory ReferenceValuesDomain MonitorInstructionsDomain MethodCallsDomain DefaultDomainValueBinding Domain Currently Available Domains ArrayValues, BaseConfigurableDomain, BaseDomain, BaseDomain, CHACallGraphDomain, CallGraphDomain, CalledTaintAnalysisDomain, ClassValues, ConstantFieldValuesResolution, DefaultArrayValuesBinding, DefaultCHACallGraphDomain, DefaultClassValuesBinding, DefaultConfigurableDomain, DefaultConfigurableDomain, DefaultDomain, DefaultDomain, DefaultDomainValueBinding, DefaultIntegerRangeValues, DefaultLongValues, DefaultPreciseIntegerValues, DefaultPreciseLongValues, DefaultReferenceValuesBinding, DefaultReferenceValuesBinding, DefaultStringValuesBinding, DefaultTypeLevelDoubleValues, DefaultTypeLevelFloatValues, DefaultTypeLevelIntegerValues, DefaultTypeLevelLongValues, DefaultTypeLevelReferenceValues, DefaultVTACallGraphDomain, Domain, IincTracingDomain, JoinStabilization, PerInstructionPostProcessing, PropertyTracing, RecordConstraints, RecordVoidReturns, ReferenceValues, ReifiedConstraints, RootTaintAnalysisDomain, SimpleBooleanPropertyTracing, StringValues, TaintAnalysisDomain, TypeLevelDomain, TypeLevelIntegerValues, VTACallGraphDomain, ValuesCoordinatingDomain The Domain used to calculate a Call Graph class DefaultCHACallGraphDomain[Source]( val project: Project[Source], val cache: CallGraphCache[MethodSignature, Set[Method]], val classFile: ClassFile, val method: Method) extends Domain with DefaultDomainValueBinding with ThrowAllPotentialExceptionsConfiguration with TheProject[Source] with TheMethod with ProjectBasedClassHierarchy with DefaultHandlingOfMethodResults with IgnoreSynchronization with l0.DefaultTypeLevelIntegerValues with l0.DefaultTypeLevelLongValues with l0.DefaultTypeLevelFloatValues with l0.DefaultTypeLevelDoubleValues with l0.DefaultReferenceValuesBinding with l0.TypeLevelFieldAccessInstructions with l0.TypeLevelInvokeInstructions with CHACallGraphDomain Most Relevant Classes of the AI Framework • AI (BaseAI) The abstract interpreter. • (Core)Domain The interface between the abstract interpreter and the user-defined/user-provided domain. • DomainValue Abstraction of a concrete runtime-value. A DomainValue is bound to its domain; the type system will ensure that domain values are not passed between different Domain instances. Parallelization • The abstract interpretation framework supports parallelization at the level of methods; i.e., it supports the concurrent abstract interpretation of multiple methods. Requirement: • the Domain contains no state that is dependent on the evaluation context • every Method is analyzed using its own Domain object (default model) A Simple Dead-Code Analysis - Idea • First, identify all if instructions. • Second, check if every branch is taken. (A branch is never taken if no state is associated with the operands/ locals on the respective branch.) A Simple Dead-Code Analysis class AnalysisDomain( override val project: Project[java.net.URL], val method: Method) extends Domain with domain.DefaultDomainValueBinding with domain.ThrowAllPotentialExceptionsConfiguration with domain.l0.DefaultTypeLevelFloatValues with domain.l0.DefaultTypeLevelDoubleValues with domain.l0.TypeLevelFieldAccessInstructions with domain.l0.TypeLevelInvokeInstructions with domain.l1.DefaultReferenceValuesBinding with domain.l1.DefaultIntegerRangeValues with domain.l1.DefaultLongValues with domain.l1.LongValuesShiftOperators with domain.l1.DefaultConcretePrimitiveValuesConversions with domain.DefaultHandlingOfMethodResults with domain.IgnoreSynchronization with domain.TheProject[java.net.URL] with domain.TheMethod with domain.ProjectBasedClassHierarchy executed in parallel A Simple Dead-Code Analysis In most cases you want to create a new domain object per analyzed method. val methodsWithDeadCode = { val results = new java.util.concurrent.ConcurrentLinkedQueue[DeadCode]() for { classFile ← theProject.classFiles.par method @ MethodWithBody(body) ← classFile.methods domain = new AnalysisDomain(theProject, method) result = BaseAI(classFile, method, domain) operandsArray = result.operandsArray (ctiPC, instruction, branchTargetPCs) ← body collectWithIndex { case (ctiPC, instruction @ ConditionalControlTransferInstruction()) if operandsArray(ctiPC) != null (ctiPC, instruction, instruction.nextInstructions(ctiPC, body)) } branchTarget ← branchTargetPCs if operandsArray(branchTarget) == null } { val operands = operandsArray(ctiPC).take(2) results.add( DeadCode(classFile, method, ctiPC, body.lineNumber(ctiPC), instruction, operands) ) } scala.collection.JavaConversions.collectionAsScalaIterable(results) } thr ea sa d fe! Scala Voodoo - Path-Dependent Types From “Programming in Scala” … As the term “path-dependent type” says, the type depends on the path: in general, different paths give rise to different types…. • The abstract interpretation framework makes heavy use of path-dependent types to ensure that (domain) values are not accidentally passed from domain to another domain/compared across domain boundaries. Scala Voodoo - Path-Dependent Types From “Programming in Scala” … As the term “path-dependent type” says, the type depends on the path: in general, different paths give rise to different types…. OPAL Example trait CoreDomain { ! trait Value { … } } val d1 = new MyDomain() val d1v = d1.IntegerRange(0,1) ! val d2 = new MyDomain() val d2v = d2.IntegerRange(0,1) ! d1v.join(d2v) If you need to compare/transfer values between domains perform an adaptation using adapt. (E.g., d1v.adapt(..d2)). It may be useful to create one (central/shared/common) Domain for this purpose. Scala Voodoo - Path-Dependent Types From “Programming in Scala” … As the term “path-dependent type” says, the type depends on the path: in general, different paths give rise to different types…. Pattern Matching on the Result of an Abstract Interpretation methods.foreach{m => val cf = p.classFile(m) val d = BaseAI(cf,m,new TheDomain(p,p.classFile(m),m)). domain r.allReturnedValues.foreach(_ match { case (pc, d.IntegerRange(x,y)) println(…) case _ => /***/ }) } => the domain used to perform the abstract interpretation Scala Voodoo - Self Types From “Programming in Scala” Technically, a self type is an assumed type for this whenever this is mentioned within the class. Pragmatically, a self type specifies the requirements on any concrete class the trait is mixed into. • The abstract interpretation framework uses self types to specify inter-domain dependencies. Example trait DefaultStringValuesBinding extends DefaultReferenceValuesBinding with StringValues { ! domain: } … IntegerValuesDomain with TypedValuesFactory with Configuration with ClassHierarchy Exercise • • Develop an analysis that collects all constructor calls in all methods that create an instance of java.io.File using the constructor (File(String s)) and where the parameter is a constant string. (Consider the intra-procedural case only) • The analysis should print out the name of the methods identified by the analysis. • Execute the analysis in parallel. Hint: You need to do an abstract interpretation using the domain “l1.DefaultStringValuesBinding”. import import import import import import ! java.net.URL org.opalj._ org.opalj.br._ org.opalj.br.analyses._ org.opalj.br.instructions._ org.opalj.ai._ object IdentifyResourcesAnalysis extends AnalysisExecutor { ! ! val analysis = new OneStepAnalysis[URL, BasicReport] { override def title: String = "File Object Creation Using Constant Strings" ! override def description: String = "Identifies java.io.File object instantiations using constant strings." Previous Solution ! override def doAnalyze(theProject: Project[URL], parameters: Seq[String], isInterrupted: () Boolean) = { val callSites = (for { cf ← theProject.classFiles.par m @ MethodWithBody(body) ← cf.methods } yield { val pcs = for { pc ← body.collectWithIndex { case ( pc, INVOKESPECIAL( ObjectType("java/io/File"), "<init>", SingleArgumentMethodDescriptor((ObjectType.String, VoidType))) ) pc } } yield pc (cf, m, pcs) }).filter(_._3.size > 0) BasicReport(…) } } } ! class AnalysisDomain( override val project: Project[URL], val method: Method) extends Domain with domain.TheProject[URL] with domain.TheMethod with domain.DefaultDomainValueBinding with domain.ThrowAllPotentialExceptionsConfiguration with domain.l0.DefaultTypeLevelIntegerValues with domain.l0.DefaultTypeLevelLongValues with domain.l0.DefaultTypeLevelFloatValues with domain.l0.DefaultTypeLevelDoubleValues with domain.l0.TypeLevelFieldAccessInstructions with domain.l0.TypeLevelInvokeInstructions with domain.l1.DefaultStringValuesBinding with domain.DefaultHandlingOfMethodResults with domain.IgnoreSynchronization with domain.ProjectBasedClassHierarchy val callSitesWithConstantStringParameter = for { (cf, m, pcs) ← callSites result = BaseAI(cf, m, new AnalysisDomain(theProject, m)) (pc, value) ← pcs.map(pc (pc, result.operandsArray(pc))).collect { case (pc, result.domain.StringValue(value) :: _) Solution ! (pc, value) } } yield (cf, m, pc, value) def callSiteToString(callSite: (ClassFile, Method, PC, String)): String = { val (cf, m, pc, v) = callSite cf.thisType.toJava+"{ "+m.toJava+"{"+pc+": \""+v+"\" } }" } BasicReport( callSitesWithConstantStringParameter.map(callSiteToString(_)). mkString("Methods:\n", "\n", ".\n")) } } } The OPAL Framework Static Analysis is Easy