Skip to content

Commit

Permalink
adding support to perform a data-flow analysis as required to compute…
Browse files Browse the repository at this point in the history
… the StackmapTableAttribute

Signed-off-by: Michael Eichberg <mail@michael-eichberg.de>
  • Loading branch information
Delors committed Dec 11, 2017
1 parent cbdaa49 commit 537681b
Show file tree
Hide file tree
Showing 6 changed files with 254 additions and 23 deletions.
8 changes: 7 additions & 1 deletion OPAL/ai/src/main/scala/org/opalj/ai/AI.scala
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,13 @@ abstract class AI[D <: Domain]( final val IdentifyDeadVariables: Boolean = true)

if (!method.isStatic) {
val thisType = method.classFile.thisType
val thisValue = domain.NonNullObjectValue(origin(localVariableIndex), thisType)
val thisValue =
if (method.isConstructor &&
(method.classFile.thisType ne ObjectType.Object))
// ... we have an uninitialized this!
domain.NewObject(origin(localVariableIndex), thisType)
else
domain.NonNullObjectValue(origin(localVariableIndex), thisType)
locals.set(localVariableIndex, thisValue)
localVariableIndex += 1 /*==thisType.computationalType.operandSize*/
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,13 @@ trait ReferenceValuesFactory extends ExceptionsFactory { domain ⇒
/**
* Creates a new `DomainValue` that represents ''a new,
* uninitialized instance of an object of the given type''. The object was
* created by the (`NEW`) instruction with the specified program counter.
* created by the (`NEW`) instruction with the specified program counter or - if value
* origin is -1 - represents this in a constructor call before the call of the super
* constructor.
*
* OPAL calls this method when it evaluates `newobject` instructions.
* If the bytecode is valid a call of one of the object's constructors will
* OPAL calls this method when it evaluates `newobject` instructions or creates the initial
* locals of constructors.
* If the bytecode is valid a call of one of the (super) object's constructors will
* subsequently initialize the object.
*
* ==Summary==
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,16 +258,22 @@ trait DefaultTypeLevelReferenceValues
StructuralUpdate(ObjectValue(pc, newUpperTypeBound))
}

final override def length(pc: PC): Computation[DomainValue, ExceptionValue] = {
throw DomainException("arraylength not possible; this is not an array value: "+this)
}

final override def load(pc: PC, index: DomainValue): ArrayLoadResult = {
throw DomainException("arrayload not possible; this is not an array value: "+this)
}

final override def store(pc: PC, value: DomainValue, index: DomainValue): ArrayStoreResult =
final override def store(
pc: PC,
value: DomainValue,
index: DomainValue
): ArrayStoreResult = {
throw DomainException("arraystore not possible; this is not an array value: "+this)

final override def length(pc: PC): Computation[DomainValue, ExceptionValue] = {
throw DomainException("arraylength not possible; this is not an array value: "+this)
}

}

protected class SObjectValue(
Expand Down Expand Up @@ -431,8 +437,7 @@ trait DefaultTypeLevelReferenceValues
// Yes is not possible here!

case No if (
supertype.isArrayType &&
upperTypeBound != ObjectType.SerializableAndCloneable
supertype.isArrayType && upperTypeBound != ObjectType.SerializableAndCloneable
)
// even if the upper bound is not precise we are now 100% sure
// that this value is not a subtype of the given supertype
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* BSD 2-Clause License:
* Copyright (c) 2009 - 2017
* Software Technology Group
* Department of Computer Science
* Technische Universität Darmstadt
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.opalj.ai.domain.l0

import org.opalj.ai.TheClassHierarchy
import org.opalj.ai.domain.ThrowAllPotentialExceptionsConfiguration
import org.opalj.ai.domain.IgnoreSynchronization
import org.opalj.ai.domain.TheMethod
import org.opalj.br.Method
import org.opalj.br.ClassHierarchy
import org.opalj.br.analyses.SomeProject

/**
* This is the domain that can be used to compute the information required to compute the
* [[org.opalj.br.StackMapTable]]
*/
class TypeCheckingDomain(
val classHierarchy: ClassHierarchy,
val method: Method
) extends TypeLevelDomain
with ThrowAllPotentialExceptionsConfiguration
with IgnoreSynchronization
with DefaultTypeLevelHandlingOfMethodResults
with TheClassHierarchy
with TheMethod {

def this(project: SomeProject, method: Method) {
this(project.classHierarchy, method)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/* BSD 2-Clause License:
* Copyright (c) 2009 - 2017
* Software Technology Group
* Department of Computer Science
* Technische Universität Darmstadt
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.opalj
package ai
package domain
package l0

import scala.reflect.ClassTag

import org.opalj.collection.immutable.UIDSet
import org.opalj.br.ArrayType
import org.opalj.br.ObjectType

/**
* Default implementation for handling reference values in such a way that we can compute
* the type information required to construct the StackMapTable attribute.
*
* @author Michael Eichberg
*/
trait TypeCheckingReferenceValues
extends DefaultTypeLevelReferenceValues
with DefaultExceptionsFactory {
domain: IntegerValuesDomain with TypedValuesFactory with Configuration with TheClassHierarchy

type AReferenceValue = ReferenceValue
type DomainReferenceValue = AReferenceValue

final val DomainReferenceValue: ClassTag[DomainReferenceValue] = implicitly

type DomainNullValue = NullValue
type DomainObjectValue = ObjectValue
type DomainArrayValue = ArrayValue

val TheNullValue: DomainNullValue = new NullValue()

// -----------------------------------------------------------------------------------
//
// REPRESENTATION OF REFERENCE VALUES
//
// -----------------------------------------------------------------------------------

protected class InitializedObjectValue(
theUpperTypeBound: ObjectType
) extends SObjectValue(theUpperTypeBound) {
this: DomainObjectValue

// WIDENING OPERATION
override protected def doJoin(pc: PC, other: DomainValue): Update[DomainValue] = {
val thisUpperTypeBound = this.theUpperTypeBound
other match {
case _: UninitializedObjectValue MetaInformationUpdateIllegalValue
case that super.doJoin(pc, that)
}
}
}

/**
* @param pc The pc of the new instruction or -1 if this represents "uninitialized size".
*/
protected case class UninitializedObjectValue(
theType: ObjectType,
pc: PC
) extends SObjectValue(theType) {
this: DomainObjectValue

override def isPrecise: Boolean = true

// joins of an uninitialized value with null results in an illegal value
override def isNull: Answer = No

// WIDENING OPERATION
override protected def doJoin(pc: PC, other: DomainValue): Update[DomainValue] = {
other match {
case UninitializedObjectValue(`theType`, `pc`) NoUpdate
// this value is not completely useable...
case _ MetaInformationUpdateIllegalValue
}
}

override def abstractsOver(other: DomainValue): Boolean = {
other match {
case that: UninitializedObjectValue if (
(that.theType eq this.theType) && this.pc == that.pc
)
true
case _
false
}
}

override def adapt(target: TargetDomain, origin: ValueOrigin): target.DomainValue = {
target.NewObject(origin, theUpperTypeBound)
}

}

// -----------------------------------------------------------------------------------
//
// FACTORY METHODS
//
// -----------------------------------------------------------------------------------

override def NullValue(origin: ValueOrigin): DomainNullValue = TheNullValue

override def NewObject(pc: PC, objectType: ObjectType): DomainObjectValue = {
new UninitializedObjectValue(objectType, pc)
}

override def InitializedObjectValue(pc: PC, objectType: ObjectType): DomainObjectValue = {
new InitializedObjectValue(objectType)
}

override def ObjectValue(origin: ValueOrigin, objectType: ObjectType): DomainObjectValue = {
new InitializedObjectValue(objectType)
}

override def ObjectValue(
origin: ValueOrigin,
upperTypeBound: UIDSet[ObjectType]
): DomainObjectValue = {
if (upperTypeBound.isSingletonSet)
ObjectValue(origin, upperTypeBound.head)
else
new MObjectValue(upperTypeBound)
}

override def ArrayValue(origin: ValueOrigin, arrayType: ArrayType): DomainArrayValue = {
new ArrayValue(arrayType)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -719,34 +719,34 @@ trait TypeLevelReferenceValues extends GeneralizedArrayHandling with AsJavaObjec

override def NullValue(pc: PC): DomainNullValue

override def NewObject(pc: PC, objectType: ObjectType): DomainObjectValue = {
ObjectValue(pc, objectType)
}

override def InitializedObjectValue(pc: PC, objectType: ObjectType): DomainObjectValue = {
ObjectValue(pc, objectType)
}

final override def ReferenceValue(
pc: PC,
upperTypeBound: ReferenceType
): AReferenceValue = {
if (upperTypeBound.isArrayType)
ArrayValue(pc, upperTypeBound.asArrayType)
else
ObjectValue(pc, upperTypeBound.asObjectType)
InitializedObjectValue(pc, upperTypeBound.asObjectType)
}

override def NonNullObjectValue(pc: PC, objectType: ObjectType): DomainObjectValue = {
ObjectValue(pc, objectType)
}

override def NewObject(pc: PC, objectType: ObjectType): DomainObjectValue = {
ObjectValue(pc, objectType)
}

override def InitializedObjectValue(pc: PC, objectType: ObjectType): DomainObjectValue = {
ObjectValue(pc, objectType)
InitializedObjectValue(pc, objectType)
}

override def StringValue(pc: PC, value: String): DomainObjectValue = {
ObjectValue(pc, ObjectType.String)
InitializedObjectValue(pc, ObjectType.String)
}

override def ClassValue(pc: PC, t: Type): DomainObjectValue = {
ObjectValue(pc, ObjectType.Class)
InitializedObjectValue(pc, ObjectType.Class)
}

//
Expand Down Expand Up @@ -785,6 +785,8 @@ trait TypeLevelReferenceValues extends GeneralizedArrayHandling with AsJavaObjec
* The properties of the domain value are:
*
* - Initialized: '''Unknown'''
* (I.e., it is not guaranteed that the constructor was called; unless newObject was
* overridden!)
* - Type: '''Upper Bound'''
* - Null: '''Unknown'''
* - Content: '''Unknown'''
Expand All @@ -801,7 +803,9 @@ trait TypeLevelReferenceValues extends GeneralizedArrayHandling with AsJavaObjec
* ==Summary==
* The properties of the domain value are:
*
* - Initialized: '''Unknown''' (i.e., it is not guaranteed that the constructor was called.)
* - Initialized: '''Unknown'''
* (I.e., it is not guaranteed that the constructor was called; unless newObject was
* overridden!)
* - Type: '''Upper Bound'''
* - Null: '''Unknown'''
* - Content: '''Unknown'''
Expand Down

0 comments on commit 537681b

Please sign in to comment.