From 7571dbdb09fa75ef7f4cb5706c58bc3e7e1dcc71 Mon Sep 17 00:00:00 2001 From: DaniilStepanov Date: Wed, 23 Aug 2023 16:28:57 +0300 Subject: [PATCH] More fixes according to PR changes request: 1. Api refactoring 2. Other minor improvements --- settings.gradle.kts | 1 - .../executor/InstrumentationProcessRunner.kt | 8 +- .../executor/RdProcessRunner.kt | 4 +- .../InstrumentedProcessModel.Generated.kt | 16 +- .../instrumentation/rd/InstrumentedProcess.kt | 4 +- .../usvm/instrumentation/rd/UTestExecutor.kt | 6 +- .../serializer/SerializationContext.kt | 8 +- ...onSerializer.kt => UTestInstSerializer.kt} | 271 ++++++++++-------- .../UTestValueDescriptorSerializer.kt | 4 - .../serializer/serializationUtils.kt | 2 + .../usvm/instrumentation/testcase/UTest.kt | 3 +- .../usvm/instrumentation/testcase/api/api.kt | 79 ++--- .../descriptor/Value2DescriptorConverter.kt | 17 +- .../executor/UTestExpressionExecutor.kt | 43 ++- .../usvm/instrumentation/util/constants.kt | 4 +- .../models/InstrumentedProcessModel.kt | 16 +- .../usvm/instrumentation/util/UTestCreator.kt | 2 +- .../kotlin/org/usvm/util/JcTestExecutor.kt | 22 +- 18 files changed, 288 insertions(+), 222 deletions(-) rename usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/{UTestExpressionSerializer.kt => UTestInstSerializer.kt} (74%) diff --git a/settings.gradle.kts b/settings.gradle.kts index 465d0654b7..ecafbe540c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,7 +5,6 @@ include("usvm-jvm") include("usvm-util") include("usvm-jvm-instrumentation") include("usvm-sample-language") -include("usvm-fuzzer") include("usvm-jvm") pluginManagement { diff --git a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/executor/InstrumentationProcessRunner.kt b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/executor/InstrumentationProcessRunner.kt index 2f8bed2e4e..9a2b7572a2 100644 --- a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/executor/InstrumentationProcessRunner.kt +++ b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/executor/InstrumentationProcessRunner.kt @@ -52,14 +52,16 @@ class InstrumentationProcessRunner( listOf(instrumentedProcessClassName) } - private fun createWorkerProcessArgs(rdPort: Int, timeout: Int): List = - listOf("-cp", testingProjectClasspath) + listOf("-t", "$timeout") + listOf("-p", "$rdPort") + private fun createWorkerProcessArgs(rdPort: Int): List = + listOf("-cp", testingProjectClasspath) + + listOf("-t", "${InstrumentationModuleConstants.concreteExecutorProcessTimeout}") + + listOf("-p", "$rdPort") suspend fun init(parentLifetime: Lifetime) { val processLifetime = LifetimeDefinition(parentLifetime) lifetime = processLifetime val rdPort = NetUtils.findFreePort(0) - val workerCommand = jvmArgs + createWorkerProcessArgs(rdPort, 120) + val workerCommand = jvmArgs + createWorkerProcessArgs(rdPort) val pb = ProcessBuilder(workerCommand).inheritIO() val process = pb.start() rdProcessRunner = diff --git a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/executor/RdProcessRunner.kt b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/executor/RdProcessRunner.kt index 70b4060c81..6bf707c4c5 100644 --- a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/executor/RdProcessRunner.kt +++ b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/executor/RdProcessRunner.kt @@ -15,7 +15,7 @@ import org.usvm.instrumentation.generated.models.* import org.usvm.instrumentation.rd.* import org.usvm.instrumentation.util.findFieldByFullNameOrNull import org.usvm.instrumentation.serializer.SerializationContext -import org.usvm.instrumentation.serializer.UTestExpressionSerializer.Companion.registerUTestExpressionSerializer +import org.usvm.instrumentation.serializer.UTestInstSerializer.Companion.registerUTestInstSerializer import org.usvm.instrumentation.serializer.UTestValueDescriptorSerializer.Companion.registerUTestValueDescriptorSerializer import org.usvm.instrumentation.testcase.UTest import org.usvm.instrumentation.testcase.api.* @@ -53,7 +53,7 @@ class RdProcessRunner( private suspend fun initRdProcess(): RdServerProcess { val serializers = Serializers() - serializers.registerUTestExpressionSerializer(serializationContext) + serializers.registerUTestInstSerializer(serializationContext) serializers.registerUTestValueDescriptorSerializer(serializationContext) val protocol = Protocol( "usvm-executor", diff --git a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/generated/models/InstrumentedProcessModel.Generated.kt b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/generated/models/InstrumentedProcessModel.Generated.kt index 8610e36f54..e09965e527 100644 --- a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/generated/models/InstrumentedProcessModel.Generated.kt +++ b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/generated/models/InstrumentedProcessModel.Generated.kt @@ -1,4 +1,4 @@ -@file:Suppress("EXPERIMENTAL_API_USAGE","EXPERIMENTAL_UNSIGNED_LITERALS","PackageDirectoryMismatch","UnusedImport","unused","LocalVariableName","CanBeVal","PropertyName","EnumEntryName","ClassName","ObjectPropertyName","UnnecessaryVariable","SpellCheckingInspection", "UNUSED_PARAMETER", "UNCHECKED_CAST") +@file:Suppress("EXPERIMENTAL_API_USAGE","EXPERIMENTAL_UNSIGNED_LITERALS","PackageDirectoryMismatch","UnusedImport","unused","LocalVariableName","CanBeVal","PropertyName","EnumEntryName","ClassName","ObjectPropertyName","UnnecessaryVariable","SpellCheckingInspection") package org.usvm.instrumentation.generated.models import com.jetbrains.rd.framework.* @@ -53,7 +53,7 @@ class InstrumentedProcessModel private constructor( } - const val serializationHash = 6309547925889624776L + const val serializationHash = 7810505090720773366L } override val serializersOwner: ISerializersOwner get() = InstrumentedProcessModel @@ -477,8 +477,8 @@ data class SerializedStaticField ( * #### Generated from [InstrumentedProcessModel.kt:42] */ data class SerializedUTest ( - val initStatements: List, - val callMethodExpression: org.usvm.instrumentation.testcase.api.UTestExpression + val initStatements: List, + val callMethodExpression: org.usvm.instrumentation.testcase.api.UTestInst ) : IPrintable { //companion @@ -487,14 +487,14 @@ data class SerializedUTest ( @Suppress("UNCHECKED_CAST") override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): SerializedUTest { - val initStatements = buffer.readList { (ctx.serializers.get(org.usvm.instrumentation.serializer.UTestExpressionSerializer.marshallerId)!! as IMarshaller).read(ctx, buffer) } - val callMethodExpression = (ctx.serializers.get(org.usvm.instrumentation.serializer.UTestExpressionSerializer.marshallerId)!! as IMarshaller).read(ctx, buffer) + val initStatements = buffer.readList { (ctx.serializers.get(org.usvm.instrumentation.serializer.UTestInstSerializer.marshallerId)!! as IMarshaller).read(ctx, buffer) } + val callMethodExpression = (ctx.serializers.get(org.usvm.instrumentation.serializer.UTestInstSerializer.marshallerId)!! as IMarshaller).read(ctx, buffer) return SerializedUTest(initStatements, callMethodExpression) } override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: SerializedUTest) { - buffer.writeList(value.initStatements) { v -> (ctx.serializers.get(org.usvm.instrumentation.serializer.UTestExpressionSerializer.marshallerId)!! as IMarshaller).write(ctx,buffer, v) } - (ctx.serializers.get(org.usvm.instrumentation.serializer.UTestExpressionSerializer.marshallerId)!! as IMarshaller).write(ctx,buffer, value.callMethodExpression) + buffer.writeList(value.initStatements) { v -> (ctx.serializers.get(org.usvm.instrumentation.serializer.UTestInstSerializer.marshallerId)!! as IMarshaller).write(ctx,buffer, v) } + (ctx.serializers.get(org.usvm.instrumentation.serializer.UTestInstSerializer.marshallerId)!! as IMarshaller).write(ctx,buffer, value.callMethodExpression) } diff --git a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/rd/InstrumentedProcess.kt b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/rd/InstrumentedProcess.kt index 60e3f2bc2b..a5b941319b 100644 --- a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/rd/InstrumentedProcess.kt +++ b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/rd/InstrumentedProcess.kt @@ -18,7 +18,7 @@ import org.jacodb.impl.jacodb import org.usvm.instrumentation.generated.models.* import org.usvm.instrumentation.instrumentation.JcInstructionTracer import org.usvm.instrumentation.serializer.SerializationContext -import org.usvm.instrumentation.serializer.UTestExpressionSerializer.Companion.registerUTestExpressionSerializer +import org.usvm.instrumentation.serializer.UTestInstSerializer.Companion.registerUTestInstSerializer import org.usvm.instrumentation.serializer.UTestValueDescriptorSerializer.Companion.registerUTestValueDescriptorSerializer import org.usvm.instrumentation.testcase.UTest import org.usvm.instrumentation.testcase.api.* @@ -97,7 +97,7 @@ class InstrumentedProcess private constructor() { private suspend fun initiate(lifetime: Lifetime, port: Int) { val scheduler = SingleThreadScheduler(lifetime, "usvm-executor-worker-scheduler") val serializers = Serializers() - serializers.registerUTestExpressionSerializer(serializationCtx) + serializers.registerUTestInstSerializer(serializationCtx) serializers.registerUTestValueDescriptorSerializer(serializationCtx) val protocol = Protocol( "usvm-executor-worker", diff --git a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/rd/UTestExecutor.kt b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/rd/UTestExecutor.kt index 02c3d07a21..81502b4986 100644 --- a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/rd/UTestExecutor.kt +++ b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/rd/UTestExecutor.kt @@ -53,7 +53,7 @@ class UTestExecutor( val accessedStatics = mutableSetOf>() val callMethodExpr = uTest.callMethodExpression val executor = UTestExpressionExecutor(workerClassLoader, accessedStatics, mockHelper) - executor.executeUTestExpressions(uTest.initStatements) + executor.executeUTestInsts(uTest.initStatements) ?.onFailure { return UTestExecutionInitFailedResult( cause = buildExceptionDescriptor(initStateDescriptorBuilder, it, false), @@ -68,7 +68,7 @@ class UTestExecutor( accessedStatics = hashSetOf() ) - executor.executeUTestExpressions(uTest.initStatements) + executor.executeUTestInsts(uTest.initStatements) ?.onFailure { return UTestExecutionInitFailedResult( cause = buildExceptionDescriptor(initStateDescriptorBuilder, it, false), @@ -77,7 +77,7 @@ class UTestExecutor( } val methodInvocationResult = - executor.executeUTestExpression(callMethodExpr) + executor.executeUTestInst(callMethodExpr) val resultStateDescriptorBuilder = Value2DescriptorConverter(workerClassLoader, initStateDescriptorBuilder) val unpackedInvocationResult = diff --git a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/SerializationContext.kt b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/SerializationContext.kt index 69edf3773e..fe4d2ddac4 100644 --- a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/SerializationContext.kt +++ b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/SerializationContext.kt @@ -2,19 +2,19 @@ package org.usvm.instrumentation.serializer import org.jacodb.api.JcClasspath import org.usvm.instrumentation.testcase.descriptor.UTestValueDescriptor -import org.usvm.instrumentation.testcase.api.UTestExpression +import org.usvm.instrumentation.testcase.api.UTestInst import java.util.* class SerializationContext( val jcClasspath: JcClasspath, ) { - val serializedUTestExpressions = IdentityHashMap() - val deserializerCache: MutableMap = hashMapOf() + val serializedUTestInstructions = IdentityHashMap() + val deserializerCache: MutableMap = hashMapOf() val serializedDescriptors = IdentityHashMap() val deserializedDescriptors = HashMap() fun reset() { - serializedUTestExpressions.clear() + serializedUTestInstructions.clear() serializedDescriptors.clear() deserializerCache.clear() deserializedDescriptors.clear() diff --git a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/UTestExpressionSerializer.kt b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/UTestInstSerializer.kt similarity index 74% rename from usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/UTestExpressionSerializer.kt rename to usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/UTestInstSerializer.kt index 2f05c90443..dc543dd467 100644 --- a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/UTestExpressionSerializer.kt +++ b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/UTestInstSerializer.kt @@ -5,70 +5,63 @@ import org.jacodb.api.* import org.jacodb.api.ext.* import org.usvm.instrumentation.util.stringType import org.usvm.instrumentation.testcase.api.* -import readJcClass -import readJcField -import readJcMethod -import readJcType -import writeJcClass -import writeJcField -import writeJcMethod -import writeJcType -class UTestExpressionSerializer(private val ctx: SerializationContext) { +class UTestInstSerializer(private val ctx: SerializationContext) { private val jcClasspath = ctx.jcClasspath - fun serialize(buffer: AbstractBuffer, uTestExpression: UTestExpression) { - buffer.serializeUTestExpression(uTestExpression) + fun serialize(buffer: AbstractBuffer, uTestInst: UTestInst) { + buffer.serializeUTestInst(uTestInst) buffer.writeEnum(UTestExpressionKind.SERIALIZED) - buffer.writeInt(uTestExpression.id) - } - - private fun AbstractBuffer.serializeUTestExpressionList(uTestExpressions: List) = - uTestExpressions.forEach { serializeUTestExpression(it) } - - private fun AbstractBuffer.serializeUTestExpression(uTestExpression: UTestExpression) { - if (ctx.serializedUTestExpressions.contains(uTestExpression)) return - when (uTestExpression) { - is UTestArrayLengthExpression -> serialize(uTestExpression) - is UTestArrayGetExpression -> serialize(uTestExpression) - is UTestAllocateMemoryCall -> serialize(uTestExpression) - is UTestConstructorCall -> serialize(uTestExpression) - is UTestMethodCall -> serialize(uTestExpression) - is UTestStaticMethodCall -> serialize(uTestExpression) - is UTestCastExpression -> serialize(uTestExpression) - is UTestNullExpression -> serialize(uTestExpression) - is UTestStringExpression -> serialize(uTestExpression) - is UTestGetFieldExpression -> serialize(uTestExpression) - is UTestGetStaticFieldExpression -> serialize(uTestExpression) - is UTestMockObject -> serialize(uTestExpression) - is UTestGlobalMock -> serialize(uTestExpression) - is UTestBinaryConditionExpression -> serialize(uTestExpression) - is UTestSetFieldStatement -> serialize(uTestExpression) - is UTestSetStaticFieldStatement -> serialize(uTestExpression) - is UTestArraySetStatement -> serialize(uTestExpression) - is UTestCreateArrayExpression -> serialize(uTestExpression) - is UTestBooleanExpression -> serialize(uTestExpression) - is UTestByteExpression -> serialize(uTestExpression) - is UTestCharExpression -> serialize(uTestExpression) - is UTestDoubleExpression -> serialize(uTestExpression) - is UTestFloatExpression -> serialize(uTestExpression) - is UTestIntExpression -> serialize(uTestExpression) - is UTestLongExpression -> serialize(uTestExpression) - is UTestShortExpression -> serialize(uTestExpression) - is UTestArithmeticExpression -> serialize(uTestExpression) - is UTestClassExpression -> serialize(uTestExpression) + buffer.writeInt(uTestInst.id) + } + + private fun AbstractBuffer.serializeUTestInstList(uTestInstructions: List) = + uTestInstructions.forEach { serializeUTestInst(it) } + + private fun AbstractBuffer.serializeUTestInst(uTestInst: UTestInst) { + if (ctx.serializedUTestInstructions.contains(uTestInst)) return + when (uTestInst) { + is UTestArrayLengthExpression -> serialize(uTestInst) + is UTestArrayGetExpression -> serialize(uTestInst) + is UTestAllocateMemoryCall -> serialize(uTestInst) + is UTestConstructorCall -> serialize(uTestInst) + is UTestMethodCall -> serialize(uTestInst) + is UTestStaticMethodCall -> serialize(uTestInst) + is UTestCastExpression -> serialize(uTestInst) + is UTestNullExpression -> serialize(uTestInst) + is UTestStringExpression -> serialize(uTestInst) + is UTestGetFieldExpression -> serialize(uTestInst) + is UTestGetStaticFieldExpression -> serialize(uTestInst) + is UTestMockObject -> serialize(uTestInst) + is UTestGlobalMock -> serialize(uTestInst) + is UTestBinaryConditionExpression -> serialize(uTestInst) + is UTestBinaryConditionStatement -> serialize(uTestInst) + is UTestSetFieldStatement -> serialize(uTestInst) + is UTestSetStaticFieldStatement -> serialize(uTestInst) + is UTestArraySetStatement -> serialize(uTestInst) + is UTestCreateArrayExpression -> serialize(uTestInst) + is UTestBooleanExpression -> serialize(uTestInst) + is UTestByteExpression -> serialize(uTestInst) + is UTestCharExpression -> serialize(uTestInst) + is UTestDoubleExpression -> serialize(uTestInst) + is UTestFloatExpression -> serialize(uTestInst) + is UTestIntExpression -> serialize(uTestInst) + is UTestLongExpression -> serialize(uTestInst) + is UTestShortExpression -> serialize(uTestInst) + is UTestArithmeticExpression -> serialize(uTestInst) + is UTestClassExpression -> serialize(uTestInst) } } - private fun AbstractBuffer.deserializeUTestExpressionFromBuffer(): UTestExpression { + private fun AbstractBuffer.deserializeUTestInstFromBuffer(): UTestInst { while (true) { val kind = readEnum() val id = readInt() val deserializedExpression = when (kind) { UTestExpressionKind.SERIALIZED -> { - return getUTestExpression(id) + return getUTestInst(id) } UTestExpressionKind.METHOD_CALL -> deserializeMethodCall() UTestExpressionKind.CONSTRUCTOR_CALL -> deserializeConstructorCall() @@ -76,7 +69,8 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { UTestExpressionKind.ARRAY_SET -> deserializeUTestArraySetStatement() UTestExpressionKind.SET_STATIC_FIELD -> deserializeUTestSetStaticFieldStatement() UTestExpressionKind.SET_FIELD -> deserializeUTestSetFieldStatement() - UTestExpressionKind.BINARY_CONDITION -> deserializeUTestBinaryConditionExpression() + UTestExpressionKind.BINARY_CONDITION_EXPR -> deserializeUTestBinaryConditionExpression() + UTestExpressionKind.BINARY_CONDITION_STATEMENT -> deserializeUTestBinaryConditionStatement() UTestExpressionKind.MOCK_OBJECT -> deserializeUTestMockObject() UTestExpressionKind.GLOBAL_MOCK -> deserializeUTestGlobalMock() UTestExpressionKind.GET_STATIC_FIELD -> deserializeUTestGetStaticFieldExpression() @@ -104,8 +98,8 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { } } - fun deserializeUTestExpression(buffer: AbstractBuffer): UTestExpression = - buffer.deserializeUTestExpressionFromBuffer() + fun deserializeUTestInst(buffer: AbstractBuffer): UTestInst = + buffer.deserializeUTestInstFromBuffer() private fun AbstractBuffer.serialize(uTestBooleanExpression: UTestBooleanExpression) = serialize( @@ -217,8 +211,8 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { serialize( uTestExpression = uTestArrayLengthExpression, kind = UTestExpressionKind.ARRAY_LENGTH, - serializeInternals = { serializeUTestExpression(arrayInstance) }, - serialize = { writeUTestExpression(arrayInstance) } + serializeInternals = { serializeUTestInst(arrayInstance) }, + serialize = { writeUTestInst(arrayInstance) } ) @@ -232,12 +226,12 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { uTestExpression = uTestArrayGetExpression, kind = UTestExpressionKind.ARRAY_GET, serializeInternals = { - serializeUTestExpression(arrayInstance) - serializeUTestExpression(index) + serializeUTestInst(arrayInstance) + serializeUTestInst(index) }, serialize = { - writeUTestExpression(arrayInstance) - writeUTestExpression(index) + writeUTestInst(arrayInstance) + writeUTestInst(index) } ) @@ -267,7 +261,7 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { uTestExpression = uTestStaticMethodCall, kind = UTestExpressionKind.STATIC_METHOD_CALL, serializeInternals = { - serializeUTestExpressionList(args) + serializeUTestInstList(args) }, serialize = { writeUTestExpressionList(args) @@ -287,10 +281,10 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { uTestExpression = uTestCastExpression, kind = UTestExpressionKind.CAST, serializeInternals = { - serializeUTestExpression(expr) + serializeUTestInst(expr) }, serialize = { - writeUTestExpression(expr) + writeUTestInst(expr) writeJcType(type) } ) @@ -343,10 +337,10 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { serialize( uTestExpression = uTestGetFieldExpression, kind = UTestExpressionKind.GET_FIELD, - serializeInternals = { serializeUTestExpression(instance) }, + serializeInternals = { serializeUTestInst(instance) }, serialize = { writeJcField(field) - writeUTestExpression(instance) + writeUTestInst(instance) } ) @@ -374,19 +368,19 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { uTestExpression = uTestMockObject, kind = UTestExpressionKind.MOCK_OBJECT, serializeInternals = { - fields.entries.map { serializeUTestExpression(it.value) } - methods.entries.map { it.value.map { serializeUTestExpression(it) } } + fields.entries.map { serializeUTestInst(it.value) } + methods.entries.map { it.value.map { serializeUTestInst(it) } } }, serialize = { writeInt(fields.entries.size) fields.entries.map { writeJcField(it.key) - writeUTestExpression(it.value) + writeUTestInst(it.value) } writeInt(methods.entries.size) methods.entries.map { writeJcMethod(it.key) - writeList(it.value) { writeUTestExpression(it) } + writeList(it.value) { writeUTestInst(it) } } writeJcType(type) } @@ -410,19 +404,19 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { uTestExpression = uTestMockObject, kind = UTestExpressionKind.GLOBAL_MOCK, serializeInternals = { - fields.entries.map { serializeUTestExpression(it.value) } - methods.entries.map { it.value.map { serializeUTestExpression(it) } } + fields.entries.map { serializeUTestInst(it.value) } + methods.entries.map { it.value.map { serializeUTestInst(it) } } }, serialize = { writeInt(fields.entries.size) fields.entries.map { writeJcField(it.key) - writeUTestExpression(it.value) + writeUTestInst(it.value) } writeInt(methods.entries.size) methods.entries.map { writeJcMethod(it.key) - writeList(it.value) { writeUTestExpression(it) } + writeList(it.value) { writeUTestInst(it) } } writeJcType(type) } @@ -444,29 +438,57 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { private fun AbstractBuffer.serialize(uTestBinaryConditionExpression: UTestBinaryConditionExpression) = serialize( uTestExpression = uTestBinaryConditionExpression, - kind = UTestExpressionKind.BINARY_CONDITION, + kind = UTestExpressionKind.BINARY_CONDITION_EXPR, serializeInternals = { - serializeUTestExpression(lhv) - serializeUTestExpression(rhv) - serializeUTestExpressionList(uTestBinaryConditionExpression.trueBranch) - serializeUTestExpressionList(uTestBinaryConditionExpression.elseBranch) + serializeUTestInst(lhv) + serializeUTestInst(rhv) + serializeUTestInst(uTestBinaryConditionExpression.trueBranch) + serializeUTestInst(uTestBinaryConditionExpression.elseBranch) }, serialize = { - writeUTestExpression(lhv) - writeUTestExpression(rhv) + writeUTestInst(lhv) + writeUTestInst(rhv) + writeUTestInst(trueBranch) + writeUTestInst(elseBranch) + writeEnum(conditionType) + } + ) + + private fun AbstractBuffer.deserializeUTestBinaryConditionExpression(): UTestBinaryConditionExpression { + val lhv = readUTestExpression() + val rhv = readUTestExpression() + val trueBranch = readUTestExpression() + val elseBranch = readUTestExpression() + val conditionType = readEnum() + return UTestBinaryConditionExpression(conditionType, lhv, rhv, trueBranch, elseBranch) + } + + private fun AbstractBuffer.serialize(uTestBinaryConditionStatement: UTestBinaryConditionStatement) = + serialize( + uTestExpression = uTestBinaryConditionStatement, + kind = UTestExpressionKind.BINARY_CONDITION_STATEMENT, + serializeInternals = { + serializeUTestInst(lhv) + serializeUTestInst(rhv) + serializeUTestInstList(uTestBinaryConditionStatement.trueBranch) + serializeUTestInstList(uTestBinaryConditionStatement.elseBranch) + }, + serialize = { + writeUTestInst(lhv) + writeUTestInst(rhv) writeUTestStatementList(trueBranch) writeUTestStatementList(elseBranch) writeEnum(conditionType) } ) - private fun AbstractBuffer.deserializeUTestBinaryConditionExpression(): UTestBinaryConditionExpression { + private fun AbstractBuffer.deserializeUTestBinaryConditionStatement(): UTestBinaryConditionStatement { val lhv = readUTestExpression() val rhv = readUTestExpression() val trueBranch = readUTestStatementList() val elseBranch = readUTestStatementList() val conditionType = readEnum() - return UTestBinaryConditionExpression(conditionType, lhv, rhv, trueBranch, elseBranch) + return UTestBinaryConditionStatement(conditionType, lhv, rhv, trueBranch, elseBranch) } private fun AbstractBuffer.serialize(uTestArithmeticExpression: UTestArithmeticExpression) = @@ -474,13 +496,13 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { uTestExpression = uTestArithmeticExpression, kind = UTestExpressionKind.ARITHMETIC, serializeInternals = { - serializeUTestExpression(lhv) - serializeUTestExpression(rhv) + serializeUTestInst(lhv) + serializeUTestInst(rhv) }, serialize = { writeEnum(operationType) - writeUTestExpression(lhv) - writeUTestExpression(rhv) + writeUTestInst(lhv) + writeUTestInst(rhv) writeJcType(type) } ) @@ -498,13 +520,13 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { uTestExpression = uTestSetFieldStatement, kind = UTestExpressionKind.SET_FIELD, serializeInternals = { - serializeUTestExpression(instance) - serializeUTestExpression(value) + serializeUTestInst(instance) + serializeUTestInst(value) }, serialize = { writeJcField(field) - writeUTestExpression(instance) - writeUTestExpression(value) + writeUTestInst(instance) + writeUTestInst(value) } ) @@ -520,11 +542,11 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { uTestExpression = uTestSetStaticFieldStatement, kind = UTestExpressionKind.SET_FIELD, serializeInternals = { - serializeUTestExpression(value) + serializeUTestInst(value) }, serialize = { writeJcField(field) - writeUTestExpression(value) + writeUTestInst(value) } ) @@ -539,14 +561,14 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { uTestExpression = uTestArraySetStatement, kind = UTestExpressionKind.ARRAY_SET, serializeInternals = { - serializeUTestExpression(arrayInstance) - serializeUTestExpression(setValueExpression) - serializeUTestExpression(index) + serializeUTestInst(arrayInstance) + serializeUTestInst(setValueExpression) + serializeUTestInst(index) }, serialize = { - writeUTestExpression(arrayInstance) - writeUTestExpression(setValueExpression) - writeUTestExpression(index) + writeUTestInst(arrayInstance) + writeUTestInst(setValueExpression) + writeUTestInst(index) } ) @@ -562,11 +584,11 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { uTestExpression = uTestCreateArrayExpression, kind = UTestExpressionKind.CREATE_ARRAY, serializeInternals = { - serializeUTestExpression(size) + serializeUTestInst(size) }, serialize = { writeJcType(elementType) - writeUTestExpression(size) + writeUTestInst(size) } ) @@ -582,7 +604,7 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { uTestExpression = uConstructorCall, kind = UTestExpressionKind.CONSTRUCTOR_CALL, serializeInternals = { - serializeUTestExpressionList(args) + serializeUTestInstList(args) }, serialize = { writeJcMethod(method) @@ -600,12 +622,12 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { uTestExpression = uMethodCall, kind = UTestExpressionKind.METHOD_CALL, serializeInternals = { - serializeUTestExpression(instance) - args.forEach { serializeUTestExpression(it) } + serializeUTestInst(instance) + args.forEach { serializeUTestInst(it) } }, serialize = { writeJcMethod(method) - writeUTestExpression(instance) + writeUTestInst(instance) writeUTestExpressionList(args) } ) @@ -618,23 +640,23 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { } - private inline fun AbstractBuffer.serialize( + private inline fun AbstractBuffer.serialize( uTestExpression: T, kind: UTestExpressionKind, serializeInternals: T.() -> Unit, serialize: T.() -> Unit ) { - val id = ctx.serializedUTestExpressions.size + 1 - if (ctx.serializedUTestExpressions.putIfAbsent(uTestExpression, -id) != null) return + val id = ctx.serializedUTestInstructions.size + 1 + if (ctx.serializedUTestInstructions.putIfAbsent(uTestExpression, -id) != null) return uTestExpression.serializeInternals() - ctx.serializedUTestExpressions[uTestExpression] = id + ctx.serializedUTestInstructions[uTestExpression] = id writeEnum(kind) writeInt(id) uTestExpression.serialize() } - private fun AbstractBuffer.writeUTestExpression(uTestExpression: UTestExpression) { - writeInt(uTestExpression.id) + private fun AbstractBuffer.writeUTestInst(uTestInst: UTestInst) { + writeInt(uTestInst.id) } private fun AbstractBuffer.writeUTestExpressionList(uTestExpressions: List) { @@ -645,18 +667,18 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { writeIntArray(uTestStatement.map { it.id }.toIntArray()) } - private fun AbstractBuffer.readUTestExpression() = getUTestExpression(readInt()) + private fun AbstractBuffer.readUTestExpression() = getUTestInst(readInt()) as UTestExpression - private fun AbstractBuffer.readUTestExpressionList() = readIntArray().map { getUTestExpression(it) } + private fun AbstractBuffer.readUTestExpressionList() = readIntArray().map { getUTestInst(it) as UTestExpression } private fun AbstractBuffer.readUTestStatementList() = - readIntArray().map { getUTestExpression(it) as UTestStatement } + readIntArray().map { getUTestInst(it) as UTestStatement } - private fun getUTestExpression(id: Int): UTestExpression = + private fun getUTestInst(id: Int): UTestInst = ctx.deserializerCache[id] ?: error("deserialization failed") - private val UTestExpression.id - get() = ctx.serializedUTestExpressions[this] + private val UTestInst.id + get() = ctx.serializedUTestInstructions[this] ?.also { check(it > 0) { "Unexpected cyclic reference?" } } ?: error("serialization failed") @@ -669,7 +691,8 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { BYTE, CAST, CHAR, - BINARY_CONDITION, + BINARY_CONDITION_EXPR, + BINARY_CONDITION_STATEMENT, CONSTRUCTOR_CALL, CREATE_ARRAY, DOUBLE, @@ -696,7 +719,7 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { private val marshallerIdHash: Int by lazy { // convert to Int here since [FrameworkMarshallers.create] accepts an Int for id - UTestExpression::class.simpleName.getPlatformIndependentHash().toInt() + UTestInst::class.simpleName.getPlatformIndependentHash().toInt() } val marshallerId: RdId by lazy { @@ -704,20 +727,20 @@ class UTestExpressionSerializer(private val ctx: SerializationContext) { } - private fun marshaller(ctx: SerializationContext): UniversalMarshaller { - val serializer = UTestExpressionSerializer(ctx) - return FrameworkMarshallers.create( - writer = { buffer, uTestExpression -> - serializer.serialize(buffer, uTestExpression) + private fun marshaller(ctx: SerializationContext): UniversalMarshaller { + val serializer = UTestInstSerializer(ctx) + return FrameworkMarshallers.create( + writer = { buffer, uTestInst -> + serializer.serialize(buffer, uTestInst) }, reader = { buffer -> - serializer.deserializeUTestExpression(buffer) + serializer.deserializeUTestInst(buffer) }, predefinedId = marshallerIdHash ) } - fun Serializers.registerUTestExpressionSerializer(ctx: SerializationContext) { + fun Serializers.registerUTestInstSerializer(ctx: SerializationContext) { register(marshaller(ctx)) } } diff --git a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/UTestValueDescriptorSerializer.kt b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/UTestValueDescriptorSerializer.kt index 679f08b1e2..51c0759a3d 100644 --- a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/UTestValueDescriptorSerializer.kt +++ b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/UTestValueDescriptorSerializer.kt @@ -5,10 +5,6 @@ import org.jacodb.api.JcField import org.jacodb.api.ext.* import org.usvm.instrumentation.util.stringType import org.usvm.instrumentation.testcase.descriptor.* -import readJcField -import readJcType -import writeJcField -import writeJcType class UTestValueDescriptorSerializer(private val ctx: SerializationContext) { diff --git a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/serializationUtils.kt b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/serializationUtils.kt index f93471cb63..fcf4bc0058 100644 --- a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/serializationUtils.kt +++ b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/serializer/serializationUtils.kt @@ -1,3 +1,5 @@ +package org.usvm.instrumentation.serializer + import com.jetbrains.rd.framework.AbstractBuffer import org.jacodb.api.* import org.jacodb.api.ext.findClass diff --git a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/testcase/UTest.kt b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/testcase/UTest.kt index 0d0489d04b..2eac8ef2ad 100644 --- a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/testcase/UTest.kt +++ b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/testcase/UTest.kt @@ -2,9 +2,10 @@ package org.usvm.instrumentation.testcase import org.usvm.instrumentation.testcase.api.UTestCall import org.usvm.instrumentation.testcase.api.UTestExpression +import org.usvm.instrumentation.testcase.api.UTestInst class UTest( - val initStatements: List, + val initStatements: List, val callMethodExpression: UTestCall ) \ No newline at end of file diff --git a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/testcase/api/api.kt b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/testcase/api/api.kt index 14c9207c0f..063c9b3212 100644 --- a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/testcase/api/api.kt +++ b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/testcase/api/api.kt @@ -8,8 +8,11 @@ import org.jacodb.impl.types.JcArrayTypeImpl * Api for UTestExpression * Used for specifying scenario of target method execution */ -sealed class UTestExpression { - abstract val type: JcType? + +sealed interface UTestInst + +sealed interface UTestExpression: UTestInst { + val type: JcType? } @@ -17,7 +20,7 @@ sealed class UTestMock( override val type: JcType, open val fields: Map, open val methods: Map> -): UTestExpression() +): UTestExpression /** * Mock for specific object */ @@ -37,24 +40,24 @@ class UTestGlobalMock( ) : UTestMock(type, fields, methods) -sealed class UTestCall : UTestExpression() { - abstract val instance: UTestExpression? - abstract val method: JcMethod? - abstract val args: List +sealed interface UTestCall : UTestExpression { + val instance: UTestExpression? + val method: JcMethod? + val args: List } class UTestMethodCall( override val instance: UTestExpression, override val method: JcMethod, override val args: List -) : UTestCall() { +) : UTestCall { override val type: JcType? = method.enclosingClass.classpath.findTypeOrNull(method.returnType) } class UTestStaticMethodCall( override val method: JcMethod, override val args: List -) : UTestCall() { +) : UTestCall { override val instance: UTestExpression? = null override val type: JcType? = method.enclosingClass.classpath.findTypeOrNull(method.returnType) } @@ -62,65 +65,73 @@ class UTestStaticMethodCall( class UTestConstructorCall( override val method: JcMethod, override val args: List -) : UTestCall() { +) : UTestCall { override val instance: UTestExpression? = null override val type: JcType = method.enclosingClass.toType() } class UTestAllocateMemoryCall( val clazz: JcClassOrInterface -) : UTestCall() { +) : UTestCall { override val instance: UTestExpression? = null override val method: JcMethod? = null override val args: List = listOf() override val type: JcType = clazz.toType() } -sealed class UTestStatement : UTestExpression() +sealed interface UTestStatement : UTestInst class UTestSetFieldStatement( val instance: UTestExpression, val field: JcField, val value: UTestExpression -) : UTestStatement() { - override val type: JcType = field.enclosingClass.classpath.void -} +) : UTestStatement class UTestSetStaticFieldStatement( val field: JcField, val value: UTestExpression -) : UTestStatement() { - override val type: JcType = field.enclosingClass.classpath.void -} +) : UTestStatement class UTestBinaryConditionExpression( val conditionType: ConditionType, val lhv: UTestExpression, val rhv: UTestExpression, - val trueBranch: List, - val elseBranch: List -) : UTestStatement() { + val trueBranch: UTestExpression, + val elseBranch: UTestExpression +) : UTestExpression { //TODO!! What if trueBranch and elseBranch have different types of the last instruction? Shouldn't we find their LCA? + + init { + check(trueBranch.type == elseBranch.type){ "True and else branches should be equal" } + } + //Probably add functionality in jacodb? - override val type: JcType? = - trueBranch.lastOrNull()?.type?.takeIf { elseBranch.isNotEmpty() } ?: lhv.type?.classpath?.void + override val type: JcType? = trueBranch.type } +class UTestBinaryConditionStatement( + val conditionType: ConditionType, + val lhv: UTestExpression, + val rhv: UTestExpression, + val trueBranch: List, + val elseBranch: List +) : UTestStatement + class UTestArithmeticExpression( val operationType: ArithmeticOperationType, val lhv: UTestExpression, val rhv: UTestExpression, override val type: JcType -) : UTestExpression() +) : UTestExpression class UTestGetStaticFieldExpression( val field: JcField -) : UTestExpression() { +) : UTestExpression { override val type: JcType? = field.enclosingClass.classpath.findTypeOrNull(field.type) } -sealed class UTestConstExpression : UTestExpression() { +sealed class UTestConstExpression : UTestExpression { abstract val value: T } @@ -178,20 +189,20 @@ class UTestNullExpression( class UTestGetFieldExpression( val instance: UTestExpression, val field: JcField -) : UTestExpression() { +) : UTestExpression { override val type: JcType? = field.enclosingClass.classpath.findTypeOrNull(field.type) } class UTestArrayLengthExpression( val arrayInstance: UTestExpression -) : UTestExpression() { +) : UTestExpression { override val type: JcType? = arrayInstance.type?.classpath?.int } class UTestArrayGetExpression( val arrayInstance: UTestExpression, val index: UTestExpression -) : UTestExpression() { +) : UTestExpression { override val type: JcType? = (arrayInstance.type as? JcArrayType)?.elementType } @@ -199,25 +210,23 @@ class UTestArraySetStatement( val arrayInstance: UTestExpression, val index: UTestExpression, val setValueExpression: UTestExpression -) : UTestStatement() { - override val type: JcType? = (arrayInstance.type as? JcArrayType)?.elementType -} +) : UTestStatement class UTestCreateArrayExpression( val elementType: JcType, val size: UTestExpression -) : UTestExpression() { +) : UTestExpression { override val type: JcType = JcArrayTypeImpl(elementType) } class UTestCastExpression( val expr: UTestExpression, override val type: JcType -) : UTestExpression() +) : UTestExpression class UTestClassExpression( override val type: JcType -): UTestExpression() +): UTestExpression enum class ConditionType { diff --git a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/testcase/descriptor/Value2DescriptorConverter.kt b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/testcase/descriptor/Value2DescriptorConverter.kt index 279a875161..6974be97b5 100644 --- a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/testcase/descriptor/Value2DescriptorConverter.kt +++ b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/testcase/descriptor/Value2DescriptorConverter.kt @@ -37,7 +37,7 @@ open class Value2DescriptorConverter( uTestExpression: UTestExpression, testExecutor: UTestExpressionExecutor, ): Result? { - testExecutor.executeUTestExpression(uTestExpression) + testExecutor.executeUTestInst(uTestExpression) .onSuccess { return buildDescriptorResultFromAny(it) } .onFailure { return Result.failure(it) } return null @@ -83,6 +83,7 @@ open class Value2DescriptorConverter( is DoubleArray -> array(any, depth + 1) is Array<*> -> array(any, depth + 1) is Class<*> -> `class`(any) + is Throwable -> `exception`(any, depth + 1) else -> `object`(any, depth + 1) } } @@ -162,7 +163,7 @@ open class Value2DescriptorConverter( return createCyclicRef(uTestObjectDescriptor, value) { jcClass.allDeclaredFields //TODO! Decide for which fields descriptors should be build - //.filterNot { it.isFinal } + .filterNot { it.isFinal || it.isTransient } .forEach { jcField -> val jField = jcField.toJavaField(classLoader) ?: return@forEach val fieldValue = jField.getFieldValue(value) @@ -172,6 +173,18 @@ open class Value2DescriptorConverter( } } + private fun `exception`(exception: Throwable, depth: Int): UTestExceptionDescriptor { + val jcClass = jcClasspath.findClass(exception::class.java.name) + val jcType = jcClass.toType() + val stackTraceElementDescriptors = exception.stackTrace.map { buildDescriptorFromAny(it, depth) } + return UTestExceptionDescriptor( + jcType, + exception.message ?: "", + stackTraceElementDescriptors, + false + ) + } + private fun `enum`(jcClass: JcClassOrInterface, value: Any, depth: Int): UTestEnumValueDescriptor { val fields = mutableMapOf() val enumValueName = value.toString() diff --git a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/testcase/executor/UTestExpressionExecutor.kt b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/testcase/executor/UTestExpressionExecutor.kt index f49f98b70b..2b8bb5d270 100644 --- a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/testcase/executor/UTestExpressionExecutor.kt +++ b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/testcase/executor/UTestExpressionExecutor.kt @@ -1,6 +1,7 @@ @file:Suppress("UNCHECKED_CAST") package org.usvm.instrumentation.testcase.executor +import org.jacodb.api.JcArrayType import org.jacodb.api.JcField import org.jacodb.api.ext.* import org.usvm.instrumentation.classloader.WorkerClassLoader @@ -22,33 +23,33 @@ class UTestExpressionExecutor( private val jcClasspath = workerClassLoader.jcClasspath - private val executedUTestExpressions: MutableMap = hashMapOf() + private val executedUTestInstructions: MutableMap = hashMapOf() - fun removeFromCache(uTestExpression: UTestExpression) = executedUTestExpressions.remove(uTestExpression) + fun removeFromCache(uTestInst: UTestInst) = executedUTestInstructions.remove(uTestInst) - fun clearCache() = executedUTestExpressions.clear() + fun clearCache() = executedUTestInstructions.clear() - fun executeUTestExpression(uTestExpression: UTestExpression): Result = + fun executeUTestInst(uTestInst: UTestInst): Result = try { MockCollector.inExecution = true - Result.success(exec(uTestExpression)) + Result.success(exec(uTestInst)) } catch (e: Throwable) { Result.failure(e) } finally { MockCollector.inExecution = false } - fun executeUTestExpressions(uTestExpressions: List): Result? { + fun executeUTestInsts(uTestExpressions: List): Result? { var lastResult: Result? = null for (uTestExpression in uTestExpressions) { - lastResult = executeUTestExpression(uTestExpression) + lastResult = executeUTestInst(uTestExpression) if (lastResult.isFailure) return lastResult } return lastResult } - private fun exec(uTestExpression: UTestExpression) = executedUTestExpressions.getOrPut(uTestExpression) { + private fun exec(uTestExpression: UTestInst) = executedUTestInstructions.getOrPut(uTestExpression) { when (uTestExpression) { is UTestConstExpression<*> -> executeUTestConstant(uTestExpression) is UTestArrayLengthExpression -> executeUTestArrayLengthExpression(uTestExpression) @@ -64,6 +65,7 @@ class UTestExpressionExecutor( is UTestGetStaticFieldExpression -> executeUTestGetStaticFieldExpression(uTestExpression) is UTestMock -> executeUTestMock(uTestExpression) is UTestBinaryConditionExpression -> executeUTestBinaryConditionExpression(uTestExpression) + is UTestBinaryConditionStatement -> executeUTestBinaryConditionStatement(uTestExpression) is UTestSetFieldStatement -> executeUTestSetFieldStatement(uTestExpression) is UTestSetStaticFieldStatement -> executeUTestSetStaticFieldStatement(uTestExpression) is UTestArithmeticExpression -> executeUTestArithmeticExpression(uTestExpression) @@ -109,8 +111,8 @@ class UTestExpressionExecutor( val arrayInstance = exec(uTestArraySetStatement.arrayInstance) val index = exec(uTestArraySetStatement.index) as Int val setValue = exec(uTestArraySetStatement.setValueExpression) - - when (uTestArraySetStatement.type) { + val arrayElementType = (uTestArraySetStatement.arrayInstance.type as? JcArrayType)?.elementType + when (arrayElementType) { jcClasspath.boolean -> (arrayInstance as BooleanArray).set(index, setValue as Boolean) jcClasspath.byte -> (arrayInstance as ByteArray).set(index, setValue as Byte) jcClasspath.short -> (arrayInstance as ShortArray).set(index, setValue as Short) @@ -241,9 +243,26 @@ class UTestExpressionExecutor( ConditionType.GT -> (lCond as Comparable) > rCond } return if (res) { - executeUTestExpressions(uTestBinaryConditionExpression.trueBranch) + executeUTestInst(uTestBinaryConditionExpression.trueBranch) + } else { + executeUTestInst(uTestBinaryConditionExpression.elseBranch) + } + } + + private fun executeUTestBinaryConditionStatement(uTestBinaryConditionStatement: UTestBinaryConditionStatement): Any? { + val lCond = exec(uTestBinaryConditionStatement.lhv) + val rCond = exec(uTestBinaryConditionStatement.rhv) + val res = + when (uTestBinaryConditionStatement.conditionType) { + ConditionType.EQ -> lCond == rCond + ConditionType.NEQ -> lCond != rCond + ConditionType.GEQ -> (lCond as Comparable) >= rCond + ConditionType.GT -> (lCond as Comparable) > rCond + } + return if (res) { + executeUTestInsts(uTestBinaryConditionStatement.trueBranch) } else { - executeUTestExpressions(uTestBinaryConditionExpression.elseBranch) + executeUTestInsts(uTestBinaryConditionStatement.elseBranch) } } diff --git a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/util/constants.kt b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/util/constants.kt index 9927692da4..f890c278b0 100644 --- a/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/util/constants.kt +++ b/usvm-jvm-instrumentation/src/main/kotlin/org/usvm/instrumentation/util/constants.kt @@ -7,7 +7,9 @@ import kotlin.time.Duration.Companion.seconds object InstrumentationModuleConstants { //Timeout for method execution - val testExecutionTimeout = 30.seconds + val testExecutionTimeout = 10.seconds + //Timeout for executor process waiting (should be in seconds) + const val concreteExecutorProcessTimeout = 120 //If something gone wrong with RD const val triesToRecreateExecutorRdProcess = 3 //Rollback strategy diff --git a/usvm-jvm-instrumentation/src/main/rdgen/org/usvm/instrumentation/models/InstrumentedProcessModel.kt b/usvm-jvm-instrumentation/src/main/rdgen/org/usvm/instrumentation/models/InstrumentedProcessModel.kt index 1e996ee078..03eb5e9866 100644 --- a/usvm-jvm-instrumentation/src/main/rdgen/org/usvm/instrumentation/models/InstrumentedProcessModel.kt +++ b/usvm-jvm-instrumentation/src/main/rdgen/org/usvm/instrumentation/models/InstrumentedProcessModel.kt @@ -9,20 +9,20 @@ object InstrumentedProcessRoot : Root() object InstrumentedProcessModel : Ext(InstrumentedProcessRoot) { - const val uTestExpressionPackage = "org.usvm.instrumentation.testcase.api" - const val uTestExpressionClassName = "$uTestExpressionPackage.UTestExpression" + const val uTestInstPackage = "org.usvm.instrumentation.testcase.api" + const val uTestInstClassName = "$uTestInstPackage.UTestInst" const val serializersPackage = "org.usvm.instrumentation.serializer" - const val uTestExpressionSerializerMarshaller = "$serializersPackage.UTestExpressionSerializer" + const val uTestInstSerializerMarshaller = "$serializersPackage.UTestInstSerializer" const val uTestValueDescriptorPackage = "org.usvm.instrumentation.testcase.descriptor" const val uTestValueDescriptorSimpleClassName = "UTestValueDescriptor" const val uTestValueDescriptorClassName = "$uTestValueDescriptorPackage.$uTestValueDescriptorSimpleClassName" const val uTestValueDescriptorSerializerMarshaller = "$serializersPackage.UTestValueDescriptorSerializer" - private val UTestExpression = Struct.Open("UTestExpression", this, null).apply { - settings[Namespace] = uTestExpressionPackage + private val UTestInst = Struct.Open("UTestInst", this, null).apply { + settings[Namespace] = uTestInstPackage settings[Intrinsic] = KotlinIntrinsicMarshaller( - "(ctx.serializers.get($uTestExpressionSerializerMarshaller.marshallerId)!! as IMarshaller<${uTestExpressionClassName}>)" + "(ctx.serializers.get($uTestInstSerializerMarshaller.marshallerId)!! as IMarshaller<${uTestInstClassName}>)" ) } @@ -40,8 +40,8 @@ object InstrumentedProcessModel : Ext(InstrumentedProcessRoot) { } private val serializedUTest = structdef { - field("initStatements", immutableList(UTestExpression)) - field("callMethodExpression", UTestExpression) + field("initStatements", immutableList(UTestInst)) + field("callMethodExpression", UTestInst) } private val executionStateSerialized = structdef { diff --git a/usvm-jvm-instrumentation/src/test/kotlin/org/usvm/instrumentation/util/UTestCreator.kt b/usvm-jvm-instrumentation/src/test/kotlin/org/usvm/instrumentation/util/UTestCreator.kt index 7b0ed5c300..58acf6bd7e 100644 --- a/usvm-jvm-instrumentation/src/test/kotlin/org/usvm/instrumentation/util/UTestCreator.kt +++ b/usvm-jvm-instrumentation/src/test/kotlin/org/usvm/instrumentation/util/UTestCreator.kt @@ -86,7 +86,7 @@ object UTestCreator { index = UTestIntExpression(5, jcClasspath.int) ) val arg2 = UTestIntExpression(1, jcClasspath.int) - val ifExpr = UTestBinaryConditionExpression( + val ifExpr = UTestBinaryConditionStatement( ConditionType.EQ, getArrEl, UTestIntExpression(7, jcClasspath.int), diff --git a/usvm-jvm/src/test/kotlin/org/usvm/util/JcTestExecutor.kt b/usvm-jvm/src/test/kotlin/org/usvm/util/JcTestExecutor.kt index 7edd1ccb25..5196f2eb75 100644 --- a/usvm-jvm/src/test/kotlin/org/usvm/util/JcTestExecutor.kt +++ b/usvm-jvm/src/test/kotlin/org/usvm/util/JcTestExecutor.kt @@ -144,7 +144,7 @@ class JcTestExecutor( private val method: JcTypedMethod ) { - private val resolvedCache = mutableMapOf>>() + private val resolvedCache = mutableMapOf>>() fun createUTest(): UTest { val thisInstance = if (!method.isStatic) { @@ -170,11 +170,11 @@ class JcTestExecutor( } - fun resolveLValue(lvalue: ULValue, type: JcType): Pair> = + fun resolveLValue(lvalue: ULValue, type: JcType): Pair> = resolveExpr(memory.read(lvalue), type) - fun resolveExpr(expr: UExpr, type: JcType): Pair> = + fun resolveExpr(expr: UExpr, type: JcType): Pair> = when (type) { is JcPrimitiveType -> resolvePrimitive(expr, type) is JcRefType -> resolveReference(expr.asExpr(ctx.addressSort), type) @@ -183,7 +183,7 @@ class JcTestExecutor( fun resolvePrimitive( expr: UExpr, type: JcPrimitiveType - ): Pair> { + ): Pair> { val exprInModel = evaluateInModel(expr) return when (type) { ctx.cp.boolean -> UTestBooleanExpression(extractBool(exprInModel) ?: false, ctx.cp.boolean) @@ -199,7 +199,7 @@ class JcTestExecutor( }.let { it to listOf() } } - fun resolveReference(heapRef: UHeapRef, type: JcRefType): Pair> { + fun resolveReference(heapRef: UHeapRef, type: JcRefType): Pair> { val ref = evaluateInModel(heapRef) as UConcreteHeapRef if (ref.address == NULL_ADDRESS) { return UTestNullExpression(type) to listOf() @@ -224,14 +224,14 @@ class JcTestExecutor( private fun resolveArray( ref: UConcreteHeapRef, heapRef: UHeapRef, type: JcArrayType - ): Pair> { + ): Pair> { val lengthRef = UArrayLengthLValue(heapRef, ctx.arrayDescriptorOf(type)) val arrLength = resolveLValue(lengthRef, ctx.cp.int).first as UTestIntExpression val length = if (arrLength.value in 0..10_000) arrLength else UTestIntExpression(0, ctx.cp.int) // TODO hack val cellSort = ctx.typeToSort(type.elementType) - fun resolveElement(idx: Int): Pair> { + fun resolveElement(idx: Int): Pair> { val elemRef = UArrayIndexLValue(cellSort, heapRef, ctx.mkBv(idx), ctx.arrayDescriptorOf(type)) return resolveLValue(elemRef, type.elementType) } @@ -254,7 +254,7 @@ class JcTestExecutor( private fun resolveObject( ref: UConcreteHeapRef, heapRef: UHeapRef, type: JcRefType - ): Pair> { + ): Pair> { if (type.jcClass == ctx.classType.jcClass && ref.address >= INITIAL_CONCRETE_ADDRESS) { return resolveAllocatedClass(ref) @@ -268,7 +268,7 @@ class JcTestExecutor( val exprs = mutableListOf() val instance = UTestAllocateMemoryCall(type.jcClass) - val fieldSetters = mutableListOf() + val fieldSetters = mutableListOf() resolvedCache[ref.address] = instance to fieldSetters exprs.add(instance) @@ -289,7 +289,7 @@ class JcTestExecutor( return instance to fieldSetters } - private fun resolveAllocatedClass(ref: UConcreteHeapRef): Pair> { + private fun resolveAllocatedClass(ref: UConcreteHeapRef): Pair> { val classTypeField = ctx.classTypeSyntheticField val classTypeLValue = UFieldLValue(ctx.addressSort, ref, classTypeField) val classTypeRef = memory.read(classTypeLValue) as? UConcreteHeapRef @@ -299,7 +299,7 @@ class JcTestExecutor( return UTestClassExpression(classType) to listOf() } - private fun resolveAllocatedString(ref: UConcreteHeapRef): Pair> { + private fun resolveAllocatedString(ref: UConcreteHeapRef): Pair> { val valueField = ctx.stringValueField val strValueLValue = UFieldLValue(ctx.typeToSort(valueField.fieldType), ref, valueField.field) return resolveLValue(strValueLValue, valueField.fieldType)