diff --git a/OPAL/ai/src/main/scala/org/opalj/ai/AI.scala b/OPAL/ai/src/main/scala/org/opalj/ai/AI.scala index c45b0a480b..f737431444 100644 --- a/OPAL/ai/src/main/scala/org/opalj/ai/AI.scala +++ b/OPAL/ai/src/main/scala/org/opalj/ai/AI.scala @@ -271,11 +271,12 @@ abstract class AI[D <: Domain]( final val IdentifyDeadVariables: Boolean = true) val thisType = method.classFile.thisType val thisValue = if (method.isConstructor && - (method.classFile.thisType ne ObjectType.Object)) + (method.classFile.thisType ne ObjectType.Object)) { // ... we have an uninitialized this! domain.NewObject(origin(localVariableIndex), thisType) - else + } else { domain.NonNullObjectValue(origin(localVariableIndex), thisType) + } locals.set(localVariableIndex, thisValue) localVariableIndex += 1 /*==thisType.computationalType.operandSize*/ } diff --git a/OPAL/ai/src/main/scala/org/opalj/ai/domain/PostEvaluationMemoryManagement.scala b/OPAL/ai/src/main/scala/org/opalj/ai/domain/PostEvaluationMemoryManagement.scala index ac17d837de..926c3549eb 100644 --- a/OPAL/ai/src/main/scala/org/opalj/ai/domain/PostEvaluationMemoryManagement.scala +++ b/OPAL/ai/src/main/scala/org/opalj/ai/domain/PostEvaluationMemoryManagement.scala @@ -36,6 +36,9 @@ import org.opalj.br.instructions.Instruction * Provides the possibility to further update the memory layout (registers and operands) * after the execution of an instruction, but before any potential join is performed. * + * Using this domain is only safe if the (partial-)domains that use this functionality + * never interfere with each other. + * * @note If this domain is mixed in then the domain cannot be used to simultaneously analyze * multiple different methods at the same time. * @@ -56,8 +59,8 @@ trait PostEvaluationMemoryManagement extends CoreDomainFunctionality { assert(oldValue ne null) assert((newValueAfterEvaluation ne null) || (newValueAfterException ne null)) - assert(oldValue ne newValueAfterEvaluation, "it doesn't make sense to update a value with itself") - assert(oldValue ne newValueAfterException, "it doesn't make sense to update a value with itself") + assert(oldValue ne newValueAfterEvaluation, "useless self update") + assert(oldValue ne newValueAfterException, "useless self update") this.oldValue = oldValue this.newValueAfterEvaluation = newValueAfterEvaluation @@ -97,11 +100,12 @@ trait PostEvaluationMemoryManagement extends CoreDomainFunctionality { pc, instruction, oldOperands, oldLocals, targetPC, isExceptionalControlFlow, operands1, locals1 ) - } else + } else { super.afterEvaluation( pc, instruction, oldOperands, oldLocals, targetPC, isExceptionalControlFlow, newOperands, newLocals ) + } } } diff --git a/OPAL/ai/src/main/scala/org/opalj/ai/domain/l0/TypeCheckingDomain.scala b/OPAL/ai/src/main/scala/org/opalj/ai/domain/l0/TypeCheckingDomain.scala index 1a38df56e7..215c32586f 100644 --- a/OPAL/ai/src/main/scala/org/opalj/ai/domain/l0/TypeCheckingDomain.scala +++ b/OPAL/ai/src/main/scala/org/opalj/ai/domain/l0/TypeCheckingDomain.scala @@ -26,12 +26,11 @@ * 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 +package org.opalj +package ai +package domain +package 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 @@ -43,10 +42,20 @@ import org.opalj.br.analyses.SomeProject class TypeCheckingDomain( val classHierarchy: ClassHierarchy, val method: Method -) extends TypeLevelDomain +) extends Domain + with DefaultDomainValueBinding + with DefaultTypeLevelIntegerValues + with DefaultTypeLevelLongValues + with TypeLevelLongValuesShiftOperators + with TypeLevelPrimitiveValuesConversions + with DefaultTypeLevelFloatValues + with DefaultTypeLevelDoubleValues + with TypeLevelFieldAccessInstructions + with TypeLevelInvokeInstructions with ThrowAllPotentialExceptionsConfiguration with IgnoreSynchronization with DefaultTypeLevelHandlingOfMethodResults + with TypeCheckingReferenceValues // we override the handling for invokespecial... with TheClassHierarchy with TheMethod { diff --git a/OPAL/ai/src/main/scala/org/opalj/ai/domain/l0/TypeCheckingReferenceValues.scala b/OPAL/ai/src/main/scala/org/opalj/ai/domain/l0/TypeCheckingReferenceValues.scala index 4f6e003df0..b8771ec788 100644 --- a/OPAL/ai/src/main/scala/org/opalj/ai/domain/l0/TypeCheckingReferenceValues.scala +++ b/OPAL/ai/src/main/scala/org/opalj/ai/domain/l0/TypeCheckingReferenceValues.scala @@ -32,10 +32,10 @@ package domain package l0 import scala.reflect.ClassTag - import org.opalj.collection.immutable.UIDSet import org.opalj.br.ArrayType import org.opalj.br.ObjectType +import org.opalj.br.MethodDescriptor /** * Default implementation for handling reference values in such a way that we can compute @@ -45,7 +45,9 @@ import org.opalj.br.ObjectType */ trait TypeCheckingReferenceValues extends DefaultTypeLevelReferenceValues - with DefaultExceptionsFactory { + with DefaultExceptionsFactory + with MethodCallsDomain + with PostEvaluationMemoryManagement { domain: IntegerValuesDomain with TypedValuesFactory with Configuration with TheClassHierarchy ⇒ type AReferenceValue = ReferenceValue @@ -72,7 +74,6 @@ trait TypeCheckingReferenceValues // 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) @@ -118,6 +119,25 @@ trait TypeCheckingReferenceValues target.NewObject(origin, theUpperTypeBound) } + override def toString: String = s"${theType.toJava}(uninitialized;origin=$pc)" + } + + abstract override def invokespecial( + pc: PC, + declaringClass: ObjectType, + isInterface: Boolean, + name: String, + methodDescriptor: MethodDescriptor, + operands: Operands + ): MethodCallResult = { + if (name == "") { + val receiver = operands.last + // the value is now initialized and we have to update the stack/locals + val UninitializedObjectValue(theType, _) = receiver + val initializedObjectValue = new InitializedObjectValue(theType) + updateAfterExecution(receiver, initializedObjectValue, TheIllegalValue) + } + super.invokespecial(pc, declaringClass, isInterface, name, methodDescriptor, operands) } // ----------------------------------------------------------------------------------- diff --git a/OPAL/br/src/main/scala/org/opalj/br/instructions/ArrayAccessInstruction.scala b/OPAL/br/src/main/scala/org/opalj/br/instructions/ArrayAccessInstruction.scala index b75eae5c68..deb1670f1f 100644 --- a/OPAL/br/src/main/scala/org/opalj/br/instructions/ArrayAccessInstruction.scala +++ b/OPAL/br/src/main/scala/org/opalj/br/instructions/ArrayAccessInstruction.scala @@ -37,8 +37,8 @@ package instructions */ abstract class ArrayAccessInstruction extends Instruction - with ConstantLengthInstruction - with NoLabels { + with ConstantLengthInstruction + with NoLabels { final def length: Int = 1