diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/UtExecutionResult.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/UtExecutionResult.kt index 74a07c0bd1..3c8c9612df 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/UtExecutionResult.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/UtExecutionResult.kt @@ -81,11 +81,12 @@ data class UtConcreteExecutionFailure(override val exception: Throwable) : UtExe /** * Represents a failure in instrumented process - * that is not actually caused by concrete execution. + * that is not actually caused by concrete method under test call. * - * For example, failure may occured during data preparation for a concrete call. + * For example, failure may have occurred during method arguments preparation + * or statics initializers processing during object instance creation. */ -data class UtConcreteExecutionProcessedFailure(override val exception: Throwable): UtExecutionFailure() +data class UtConcreteExecutionProcessedFailure(override val exception: Throwable) : UtExecutionFailure() val UtExecutionResult.isSuccess: Boolean get() = this is UtExecutionSuccess diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt index 5e88f312c6..89d7ea8acf 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -48,14 +48,12 @@ import org.utbot.instrumentation.ConcreteExecutor 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 @@ -317,10 +315,7 @@ class UtBotSymbolicEngine( val concreteExecutionResult = concreteExecutor.executeConcretely(methodUnderTest, stateBefore, instrumentation, UtSettings.concreteExecutionDefaultTimeoutInInstrumentedProcessMillis) - concreteExecutionResult.processedFailure()?.let { failure -> - emitFailedConcreteExecutionResult(stateBefore, failure.exception) - - logger.debug { "Instrumented process failed with exception ${failure.exception} before concrete execution started" } + if (failureCanBeProcessedGracefully(concreteExecutionResult, executionToRollbackOn = null)) { return@measureTime } @@ -668,10 +663,7 @@ class UtBotSymbolicEngine( UtSettings.concreteExecutionDefaultTimeoutInInstrumentedProcessMillis ) - concreteExecutionResult.processedFailure()?.let { failure -> - emitFailedConcreteExecutionResult(stateBefore, failure.exception) - - logger.debug { "Instrumented process failed with exception ${failure.exception} before concrete execution started" } + if (failureCanBeProcessedGracefully(concreteExecutionResult, symbolicUtExecution)) { return } @@ -699,6 +691,29 @@ class UtBotSymbolicEngine( } } + private suspend fun FlowCollector.failureCanBeProcessedGracefully( + concreteExecutionResult: UtConcreteExecutionResult, + executionToRollbackOn: UtExecution?, + ): Boolean { + concreteExecutionResult.processedFailure()?.let { failure -> + // If concrete execution failed to some reasons that are not process death or cancellation + // when we call something that is processed successfully by symbolic engine, + // we should: + // - roll back to symbolic execution data ignoring failing concrete (is symbolic execution exists); + // - do not emit an execution if there is nothing to roll back on. + + // Note that this situation is suspicious anyway, so we log a WARN message about the failure. + executionToRollbackOn?.let { + emit(it) + } + + logger.warn { "Instrumented process failed with exception ${failure.exception} before concrete execution started" } + return true + } + + return false + } + /** * Collects entry method statement path for ML. Eliminates duplicated statements, e.g. assignment with invocation * in right part. diff --git a/utbot-summary/src/main/kotlin/org/utbot/summary/TagGenerator.kt b/utbot-summary/src/main/kotlin/org/utbot/summary/TagGenerator.kt index c48252aa0d..0e5947483c 100644 --- a/utbot-summary/src/main/kotlin/org/utbot/summary/TagGenerator.kt +++ b/utbot-summary/src/main/kotlin/org/utbot/summary/TagGenerator.kt @@ -207,7 +207,13 @@ enum class ExecutionGroup { EXPLICITLY_THROWN_UNCHECKED_EXCEPTIONS, OVERFLOWS, TIMEOUTS, + + /** + * Executions that caused by `InstrumentedProcessDeath` exception. + * Generated tests will be disabled du to possible JVM crash. + */ CRASH_SUITE, + TAINT_ANALYSIS, SECURITY; @@ -221,10 +227,11 @@ private fun UtExecutionResult.clusterKind() = when (this) { is UtStreamConsumingFailure -> ExecutionGroup.ERROR_SUITE is UtOverflowFailure -> ExecutionGroup.OVERFLOWS is UtTimeoutException -> ExecutionGroup.TIMEOUTS - is UtConcreteExecutionProcessedFailure -> ExecutionGroup.CRASH_SUITE is UtConcreteExecutionFailure -> ExecutionGroup.CRASH_SUITE is UtSandboxFailure -> ExecutionGroup.SECURITY is UtTaintAnalysisFailure -> ExecutionGroup.TAINT_ANALYSIS + is UtConcreteExecutionProcessedFailure -> + error("Processed failure must not be found in generated tests, it can just happen on intermediate phases of tests generation") } /**