Skip to content
Next Next commit
Add way to get instrumentation result
  • Loading branch information
egiptipavel committed Jul 28, 2023
commit 03b36a83d34cc09fb5614b7aa4803cc8818d3b78
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,16 @@ import org.utbot.fuzzer.*
import org.utbot.fuzzing.*
import org.utbot.fuzzing.utils.Trie
import org.utbot.instrumentation.ConcreteExecutor
import org.utbot.instrumentation.getInstrumentationResult
import org.utbot.instrumentation.instrumentation.Instrumentation
import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionData
import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult
import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation
import org.utbot.taint.*
import org.utbot.taint.model.TaintConfiguration
import soot.jimple.Stmt
import soot.tagkit.ParamNamesTag
import java.lang.reflect.Method
import java.util.function.Consumer
import java.util.function.Predicate
import kotlin.math.min
import kotlin.system.measureTimeMillis

Expand Down Expand Up @@ -452,6 +451,8 @@ class UtBotSymbolicEngine(
}.let(transform)

val coverageToMinStateBeforeSize = mutableMapOf<Trie.Node<Instruction>, Int>()
val instrumentationResult = concreteExecutor.getInstrumentationResult(methodUnderTest)
val needToCoverInstructionsIds = instrumentationResult.instructionsIds

runJavaFuzzing(
defaultIdGenerator,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,21 @@ import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import mu.KotlinLogging
import org.utbot.framework.plugin.api.InstrumentedProcessDeathException
import org.utbot.common.logException
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.FieldId
import org.utbot.framework.plugin.api.ConcreteContextLoadingResult
import org.utbot.framework.plugin.api.SpringRepositoryId
import org.utbot.framework.plugin.api.*
import org.utbot.framework.plugin.api.util.UtContext
import org.utbot.framework.plugin.api.util.signature
import org.utbot.instrumentation.instrumentation.Instrumentation
import org.utbot.instrumentation.instrumentation.execution.ResultOfInstrumentation
import org.utbot.instrumentation.process.generated.ComputeStaticFieldParams
import org.utbot.instrumentation.process.generated.GetResultOfInstrumentationParams
import org.utbot.instrumentation.process.generated.GetSpringRepositoriesParams
import org.utbot.instrumentation.process.generated.InvokeMethodCommandParams
import org.utbot.instrumentation.rd.InstrumentedProcess
import org.utbot.instrumentation.util.InstrumentedProcessError
import org.utbot.rd.generated.synchronizationModel
import org.utbot.rd.loggers.overrideDefaultRdLoggerFactoryWithKLogger
import org.utbot.rd.startBlocking

private val logger = KotlinLogging.logger {}

Expand Down Expand Up @@ -313,3 +312,11 @@ fun <T> ConcreteExecutor<*, *>.computeStaticField(fieldId: FieldId): Result<T> =
kryoHelper.readObject(result.result)
}
}

fun ConcreteExecutor<*, *>.getInstrumentationResult(methodUnderTest: ExecutableId): ResultOfInstrumentation = runBlocking {
withProcess {
val params = GetResultOfInstrumentationParams(methodUnderTest.classId.name, methodUnderTest.name)
val result = instrumentedProcessModel.getResultOfInstrumentation.startBlocking(params)
kryoHelper.readObject(result.result)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ package org.utbot.instrumentation.instrumentation.et

import com.jetbrains.rd.util.error
import com.jetbrains.rd.util.getLogger
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type
import org.objectweb.asm.commons.LocalVariablesSorter
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.FieldId
import org.utbot.instrumentation.Settings
import kotlin.reflect.jvm.javaField
import kotlin.reflect.jvm.javaMethod
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type
import org.objectweb.asm.commons.LocalVariablesSorter

sealed class InstructionData {
abstract val line: Int
Expand Down Expand Up @@ -65,6 +65,8 @@ class ProcessingStorage {
private val instructionsData = mutableMapOf<Long, InstructionData>()
private val classToInstructionsCount = mutableMapOf<String, Long>()

private val methodIdToInstructionsIds = mutableMapOf<Int, MutableList<Long>>()

fun addClass(className: String): Int {
val id = classToId.getOrPut(className) { classToId.size }
idToClass.putIfAbsent(id, className)
Expand All @@ -88,10 +90,16 @@ class ProcessingStorage {
return className to localId
}

fun addInstruction(id: Long, instructionData: InstructionData) {
fun addInstruction(id: Long, methodId: Int, instructionData: InstructionData) {
instructionsData.computeIfAbsent(id) {
val (className, _) = computeClassNameAndLocalId(id)
classToInstructionsCount.merge(className, 1, Long::plus)
// TODO refactor this
if (methodId !in methodIdToInstructionsIds) {
methodIdToInstructionsIds[methodId] = mutableListOf(id)
} else {
methodIdToInstructionsIds[methodId]!!.add(id)
}
instructionData
}
}
Expand All @@ -103,6 +111,11 @@ class ProcessingStorage {
return instructionsData.getValue(id)
}

fun getInstructionsIds(className: String, methodName: String): List<Long> {
val methodId = classMethodToId[ClassToMethod(className, methodName)]
return methodIdToInstructionsIds[methodId]!!
}

companion object {
private const val SHIFT = 1.toLong().shl(32) // 2 ^ 32
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class TraceListStrategy(

private fun processNewInstruction(mv: MethodVisitor, instructionData: InstructionData): MethodVisitor {
val id = nextId()
storage.addInstruction(id, instructionData)
storage.addInstruction(id, currentClassMethodId, instructionData)
return inserter.insertUtilityInstructions(mv, id)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ class SimpleUtExecutionInstrumentation(
}
}

override fun getResultOfInstrumentation(className: String, methodName: String): ResultOfInstrumentation =
ResultOfInstrumentation(traceHandler.processingStorage.getInstructionsIds(className, methodName))

override fun getStaticField(fieldId: FieldId): Result<UtModel> =
delegateInstrumentation.getStaticField(fieldId).map { value ->
UtModelConstructor.createOnlyUserClassesConstructor(pathsToUserClasses)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ data class UtConcreteExecutionResult(
}
}

data class ResultOfInstrumentation(val instructionsIds: List<Long>)

interface UtExecutionInstrumentation : Instrumentation<UtConcreteExecutionResult> {
override fun invoke(
clazz: Class<*>,
Expand All @@ -54,6 +56,8 @@ interface UtExecutionInstrumentation : Instrumentation<UtConcreteExecutionResult
phasesWrapper: PhasesController.(invokeBasePhases: () -> UtConcreteExecutionResult) -> UtConcreteExecutionResult
): UtConcreteExecutionResult

fun getResultOfInstrumentation(className: String, methodName: String): ResultOfInstrumentation

interface Factory<out TInstrumentation : UtExecutionInstrumentation> : Instrumentation.Factory<UtConcreteExecutionResult, TInstrumentation> {
override fun create(): TInstrumentation = create(SimpleInstrumentationContext())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@ import com.jetbrains.rd.util.getLogger
import com.jetbrains.rd.util.info
import org.utbot.common.JarUtils
import org.utbot.common.hasOnClasspath
import org.utbot.framework.plugin.api.BeanDefinitionData
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.FieldId
import org.utbot.framework.plugin.api.ConcreteContextLoadingResult
import org.utbot.framework.plugin.api.SpringRepositoryId
import org.utbot.framework.plugin.api.SpringSettings.*
import org.utbot.framework.plugin.api.*
import org.utbot.framework.plugin.api.SpringSettings.PresentSpringSettings
import org.utbot.framework.plugin.api.util.jClass
import org.utbot.instrumentation.instrumentation.ArgumentList
import org.utbot.instrumentation.instrumentation.execution.ResultOfInstrumentation
import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult
import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation
import org.utbot.instrumentation.instrumentation.execution.context.InstrumentationContext
Expand Down Expand Up @@ -116,17 +113,20 @@ class SpringUtExecutionInstrumentation(
protectionDomain: ProtectionDomain,
classfileBuffer: ByteArray
): ByteArray? =
// we do not transform Spring classes as it takes too much time
// we do not transform Spring classes as it takes too much time

// maybe we should still transform classes related to data validation
// (e.g. from packages "javax/persistence" and "jakarta/persistence"),
// maybe we should still transform classes related to data validation
// (e.g. from packages "javax/persistence" and "jakarta/persistence"),
// since traces from such classes can be particularly useful for feedback to fuzzer
if (userSourcesClassLoader.hasOnClasspath(className.replace("/", "."))) {
delegateInstrumentation.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer)
} else {
null
}

override fun getResultOfInstrumentation(className: String, methodName: String): ResultOfInstrumentation =
delegateInstrumentation.getResultOfInstrumentation(className, methodName)

class Factory(
private val delegateInstrumentationFactory: UtExecutionInstrumentation.Factory<*>,
private val springSettings: PresentSpringSettings,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,10 @@ import org.utbot.framework.process.kryo.KryoHelper
import org.utbot.instrumentation.agent.Agent
import org.utbot.instrumentation.instrumentation.Instrumentation
import org.utbot.instrumentation.instrumentation.coverage.CoverageInstrumentation
import org.utbot.instrumentation.instrumentation.spring.SpringUtExecutionInstrumentation
import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation
import org.utbot.instrumentation.instrumentation.execution.constructors.UtModelConstructor
import org.utbot.instrumentation.process.generated.CollectCoverageResult
import org.utbot.instrumentation.process.generated.GetSpringBeanResult
import org.utbot.instrumentation.process.generated.GetSpringRepositoriesResult
import org.utbot.instrumentation.process.generated.InstrumentedProcessModel
import org.utbot.instrumentation.process.generated.InvokeMethodCommandResult
import org.utbot.instrumentation.process.generated.TryLoadingSpringContextResult
import org.utbot.instrumentation.process.generated.instrumentedProcessModel
import org.utbot.instrumentation.instrumentation.spring.SpringUtExecutionInstrumentation
import org.utbot.instrumentation.process.generated.*
import org.utbot.rd.IdleWatchdog
import org.utbot.rd.ClientProtocolBuilder
import org.utbot.rd.RdSettingsContainerFactory
Expand Down Expand Up @@ -151,6 +146,12 @@ private fun InstrumentedProcessModel.setup(kryoHelper: KryoHelper, watchdog: Idl
Agent.dynamicClassTransformer.transformer = instrumentation
Agent.dynamicClassTransformer.addUserPaths(pathsToUserClasses)
}
watchdog.measureTimeForActiveCall(getResultOfInstrumentation, "Getting instrumentation result") { params ->
HandlerClassesLoader.loadClass(params.className)
val result = (instrumentation as UtExecutionInstrumentation)
.getResultOfInstrumentation(params.className, params.methodName)
GetResultOfInstrumentationResult(kryoHelper.writeObject(result))
}
watchdog.measureTimeForActiveCall(addPaths, "User and dependency classpath setup") { params ->
pathsToUserClasses = params.pathsToUserClasses.split(File.pathSeparatorChar).toSet()
HandlerClassesLoader.addUrls(pathsToUserClasses)
Expand Down
Loading