Skip to content

Commit 5227aff

Browse files
Contest mode is done
1 parent 59ac644 commit 5227aff

File tree

29 files changed

+470
-213
lines changed

29 files changed

+470
-213
lines changed

utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/UtExecutionResult.kt

-6
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,6 @@ sealed class UtExecutionFailure : UtExecutionResult() {
2222
get() = exception
2323
}
2424

25-
data class UtExecutionSuccessConcrete(val result: Any?) : UtExecutionResult() {
26-
override fun toString() = "$result"
27-
}
28-
2925
data class UtOverflowFailure(
3026
override val exception: Throwable,
3127
) : UtExecutionFailure()
@@ -110,11 +106,9 @@ inline fun UtExecutionResult.onFailure(action: (exception: Throwable) -> Unit):
110106
fun UtExecutionResult.getOrThrow(): UtModel = when (this) {
111107
is UtExecutionSuccess -> model
112108
is UtExecutionFailure -> throw exception
113-
is UtExecutionSuccessConcrete -> UtNullModel(objectClassId)
114109
}
115110

116111
fun UtExecutionResult.exceptionOrNull(): Throwable? = when (this) {
117112
is UtExecutionFailure -> rootCauseException
118113
is UtExecutionSuccess -> null
119-
is UtExecutionSuccessConcrete -> null
120114
}

utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt

+11-8
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ import kotlinx.coroutines.flow.FlowCollector
100100
import kotlinx.coroutines.flow.flow
101101
import kotlinx.coroutines.flow.onCompletion
102102
import kotlinx.coroutines.flow.onStart
103+
import kotlinx.coroutines.flow.emitAll
103104
import kotlinx.coroutines.isActive
104105
import kotlinx.coroutines.job
105106
import kotlinx.coroutines.yield
@@ -526,8 +527,8 @@ class UtBotSymbolicEngine(
526527
}
527528

528529
//Simple fuzzing
529-
fun greyBoxFuzzing(until: Long = Long.MAX_VALUE) =
530-
flow<UtResult> {
530+
fun greyBoxFuzzing(timeBudget: Long = Long.MAX_VALUE) =
531+
flow {
531532
GenericsInfoFactory.disableCache()
532533
val isFuzzable = methodUnderTest.parameters.all { classId ->
533534
classId != Method::class.java.id // causes the child process crash at invocation
@@ -537,12 +538,14 @@ class UtBotSymbolicEngine(
537538
}
538539

539540
try {
540-
GreyBoxFuzzer(
541-
concreteExecutor.pathsToUserClasses,
542-
concreteExecutor.pathsToDependencyClasses,
543-
methodUnderTest,
544-
120_000L
545-
).fuzz()
541+
emitAll(
542+
GreyBoxFuzzer(
543+
concreteExecutor.pathsToUserClasses,
544+
concreteExecutor.pathsToDependencyClasses,
545+
methodUnderTest,
546+
timeBudget
547+
).fuzz()
548+
)
546549
} catch (e: CancellationException) {
547550
logger.debug { "Cancelled by timeout" }
548551
} catch (e: Throwable) {

utbot-framework/src/main/kotlin/org/utbot/engine/ValueConstructor.kt

-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import org.utbot.framework.plugin.api.UtExecution
2828
import org.utbot.framework.plugin.api.UtExecutionFailure
2929
import org.utbot.framework.plugin.api.UtExecutionResult
3030
import org.utbot.framework.plugin.api.UtExecutionSuccess
31-
import org.utbot.framework.plugin.api.UtExecutionSuccessConcrete
3231
import org.utbot.framework.plugin.api.UtLambdaModel
3332
import org.utbot.framework.plugin.api.UtMockValue
3433
import org.utbot.framework.plugin.api.UtModel
@@ -495,7 +494,6 @@ class ValueConstructor {
495494
private fun <R> UtExecutionResult.map(transform: (model: UtModel) -> R): Result<R> = when (this) {
496495
is UtExecutionSuccess -> Result.success(transform(model))
497496
is UtExecutionFailure -> Result.failure(exception)
498-
is UtExecutionSuccessConcrete -> Result.success(transform(UtNullModel(Any::class.java.id)))
499497
}
500498

501499
/**

utbot-framework/src/main/kotlin/org/utbot/engine/greyboxfuzzer/GreyBoxFuzzer.kt

+48-47
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.utbot.engine.greyboxfuzzer
22

3+
import kotlinx.coroutines.flow.FlowCollector
4+
import kotlinx.coroutines.flow.flow
35
import org.utbot.engine.*
46
import org.utbot.engine.greyboxfuzzer.generator.*
57
import org.utbot.engine.greyboxfuzzer.mutator.Mutator
@@ -12,8 +14,8 @@ import org.utbot.framework.plugin.api.util.*
1214
import org.utbot.framework.util.sootMethod
1315
import org.utbot.instrumentation.ConcreteExecutor
1416
import org.utbot.engine.greyboxfuzzer.quickcheck.generator.GeneratorContext
17+
import java.lang.reflect.Executable
1518
import java.lang.reflect.Field
16-
import java.lang.reflect.Method
1719
import kotlin.random.Random
1820

1921
class GreyBoxFuzzer(
@@ -23,24 +25,19 @@ class GreyBoxFuzzer(
2325
private val timeBudgetInMillis: Long
2426
) {
2527

26-
private val methodLines =
27-
methodUnderTest.sootMethod.activeBody.units
28-
.map { it.javaSourceStartLineNumber }
29-
.filter { it != -1 }
30-
.toSet()
31-
private val seeds = SeedCollector(methodLines = methodLines)
32-
private val succeededExecutions = mutableListOf<UtGreyBoxFuzzedExecution>()
28+
private var methodInstructionsIds: Set<Long>? = null
29+
private var seeds: SeedCollector? = null
3330
private val timeRemain
3431
get() = timeOfStart + timeBudgetInMillis - System.currentTimeMillis()
3532
private val timeOfStart = System.currentTimeMillis()
36-
private val percentageOfTimeBudgetToChangeMode = 10
33+
private val percentageOfTimeBudgetToChangeMode = 25
3734

38-
suspend fun fuzz(): Sequence<UtExecution> {
35+
suspend fun fuzz() = flow {
3936
logger.debug { "Started to fuzz ${methodUnderTest.name}" }
4037
val generatorContext = GeneratorContext()
4138
val javaClazz = methodUnderTest.classId.jClass
4239
val sootMethod = methodUnderTest.sootMethod
43-
val javaMethod = sootMethod.toJavaMethod()!!
40+
val javaMethod = sootMethod.toJavaMethod() ?: return@flow
4441
val classFieldsUsedByFunc = sootMethod.getClassFieldsUsedByFunc(javaClazz)
4542
while (timeRemain > 0 || !isMethodCovered()) {
4643
explorationStage(
@@ -49,15 +46,14 @@ class GreyBoxFuzzer(
4946
methodUnderTest,
5047
generatorContext
5148
)
52-
logger.debug { "SEEDS AFTER EXPLORATION STAGE = ${seeds.seedsSize()}" }
49+
logger.debug { "SEEDS AFTER EXPLORATION STAGE = ${seeds?.seedsSize()}" }
5350
if (timeRemain < 0 || isMethodCovered()) break
5451
exploitationStage()
5552
}
56-
return succeededExecutions.asSequence()
5753
}
5854

59-
private suspend fun explorationStage(
60-
method: Method,
55+
private suspend fun FlowCollector<UtExecution>.explorationStage(
56+
method: Executable,
6157
classFieldsUsedByFunc: Set<Field>,
6258
methodUnderTest: ExecutableId,
6359
generatorContext: GeneratorContext
@@ -112,8 +108,8 @@ class GreyBoxFuzzer(
112108
parameter,
113109
index,
114110
generatorContext,
115-
GreyBoxFuzzerGenerators.sourceOfRandomness,
116-
GreyBoxFuzzerGenerators.genStatus
111+
GreyBoxFuzzerGeneratorsAndSettings.sourceOfRandomness,
112+
GreyBoxFuzzerGeneratorsAndSettings.genStatus
117113
)
118114
}
119115
logger.debug { "Generated params = $generatedParameters" }
@@ -123,23 +119,27 @@ class GreyBoxFuzzer(
123119
try {
124120
logger.debug { "Execution started" }
125121
val executionResult = execute(stateBefore, methodUnderTest)
122+
if (methodInstructionsIds == null) {
123+
methodInstructionsIds = executionResult.methodInstructionsIds
124+
seeds = SeedCollector(methodInstructionsIds = methodInstructionsIds!!)
125+
}
126+
seeds ?: continue
126127
logger.debug { "Execution result: $executionResult" }
127128
val seedCoverage = getCoverage(executionResult)
128129
logger.debug { "Calculating seed score" }
129-
val seedScore = seeds.calcSeedScore(seedCoverage)
130+
val seedScore = seeds!!.calcSeedScore(seedCoverage)
130131
logger.debug { "Adding seed" }
131132
val seed = Seed(thisInstance, generatedParameters, seedCoverage, seedScore)
132-
if (seeds.isSeedOpensNewCoverage(seed)) {
133-
succeededExecutions.add(
133+
if (seeds!!.isSeedOpensNewCoverage(seed)) {
134+
emit(
134135
UtGreyBoxFuzzedExecution(
135136
stateBefore,
136-
executionResult.result,
137-
coverage = executionResult.coverage,
138-
testMethodName = methodUnderTest.name
137+
executionResult,
138+
coverage = executionResult.coverage
139139
)
140140
)
141141
}
142-
seeds.addSeed(seed)
142+
seeds!!.addSeed(seed)
143143
logger.debug { "Execution result: ${executionResult.result}" }
144144
logger.debug { "Seed score = $seedScore" }
145145
} catch (e: Throwable) {
@@ -154,10 +154,10 @@ class GreyBoxFuzzer(
154154
}
155155
}
156156

157-
private suspend fun exploitationStage() {
157+
private suspend fun FlowCollector<UtExecution>.exploitationStage() {
158158
logger.debug { "Exploitation began" }
159-
if (seeds.seedsSize() == 0) return
160-
if (seeds.all { it.parameters.isEmpty() }) return
159+
if (seeds == null || seeds!!.seedsSize() == 0) return
160+
if (seeds!!.all { it.parameters.isEmpty() }) return
161161
val startTime = System.currentTimeMillis()
162162
val endTime = startTime + timeBudgetInMillis / percentageOfTimeBudgetToChangeMode
163163
var iterationNumber = 0
@@ -167,13 +167,13 @@ class GreyBoxFuzzer(
167167
if (iterationNumber > 30_000) return
168168
logger.debug { "Func: ${methodUnderTest.name} Mutation iteration number $iterationNumber" }
169169
iterationNumber++
170-
val randomSeed = seeds.getRandomWeightedSeed()
170+
val randomSeed = seeds!!.getRandomWeightedSeed()
171171
logger.debug { "Random seed params = ${randomSeed.parameters}" }
172172
val mutatedSeed =
173173
Mutator.mutateSeed(
174174
randomSeed,
175-
GreyBoxFuzzerGenerators.sourceOfRandomness,
176-
GreyBoxFuzzerGenerators.genStatus
175+
GreyBoxFuzzerGeneratorsAndSettings.sourceOfRandomness,
176+
GreyBoxFuzzerGeneratorsAndSettings.genStatus
177177
)
178178
if (mutatedSeed == randomSeed) {
179179
logger.debug { "Cant mutate seed" }
@@ -186,17 +186,16 @@ class GreyBoxFuzzer(
186186
logger.debug { "Execution result: $executionResult" }
187187
val seedScore = getCoverage(executionResult)
188188
mutatedSeed.score = 0.0
189-
if (seeds.isSeedOpensNewCoverage(mutatedSeed)) {
190-
succeededExecutions.add(
189+
if (seeds!!.isSeedOpensNewCoverage(mutatedSeed)) {
190+
emit(
191191
UtGreyBoxFuzzedExecution(
192192
stateBefore,
193-
executionResult.result,
194-
coverage = executionResult.coverage,
195-
testMethodName = methodUnderTest.name
193+
executionResult,
194+
coverage = executionResult.coverage
196195
)
197196
)
198197
}
199-
seeds.addSeed(mutatedSeed)
198+
seeds!!.addSeed(mutatedSeed)
200199
logger.debug { "Execution result: ${executionResult.result}" }
201200
logger.debug { "Seed score = $seedScore" }
202201
} catch (e: Throwable) {
@@ -208,23 +207,25 @@ class GreyBoxFuzzer(
208207

209208
private fun getCoverage(
210209
executionResult: UtFuzzingConcreteExecutionResult
211-
): Set<Int> {
210+
): Set<Long> {
212211
val currentMethodCoverage = executionResult.coverage.coveredInstructions
213212
.asSequence()
213+
.filter { it.className == methodUnderTest.classId.name.replace('.', '/') }
214214
.filter { it.methodSignature == methodUnderTest.signature }
215-
.map { it.lineNumber }
216-
.filter { it in methodLines }
215+
.map { it.id }
216+
.filter { it in methodInstructionsIds!! }
217217
.toSet()
218-
logger.debug { "Covered lines $currentMethodCoverage from $methodLines" }
219-
executionResult.coverage.coveredInstructions.forEach { CoverageCollector.coverage.add(it) }
218+
logger.debug { "Covered instructions ${currentMethodCoverage.count()} from ${methodInstructionsIds!!.size}" }
219+
executionResult.coverage.coveredInstructions.forEach { CoverageCollector.addCoverage(it) }
220220
return currentMethodCoverage
221221
}
222222

223223
private fun isMethodCovered(): Boolean {
224-
val coveredLines =
225-
CoverageCollector.coverage.filter { it.methodSignature == methodUnderTest.signature }.map { it.lineNumber }
224+
methodInstructionsIds ?: return false
225+
val coveredInstructions =
226+
CoverageCollector.coverage.filter { it.methodSignature == methodUnderTest.signature }.map { it.id }
226227
.toSet()
227-
return coveredLines.containsAll(methodLines)
228+
return coveredInstructions.containsAll(methodInstructionsIds!!)
228229
}
229230

230231
private suspend fun ConcreteExecutor<UtFuzzingConcreteExecutionResult, UtFuzzingExecutionInstrumentation>.executeConcretely(
@@ -253,12 +254,12 @@ class GreyBoxFuzzer(
253254

254255

255256
private fun generateThisInstance(classId: ClassId, generatorContext: GeneratorContext): ThisInstance =
256-
if (!methodUnderTest.isStatic) {
257+
if (!methodUnderTest.isStatic && !methodUnderTest.isConstructor) {
257258
DataGenerator.generateThis(
258259
classId,
259260
generatorContext,
260-
GreyBoxFuzzerGenerators.sourceOfRandomness,
261-
GreyBoxFuzzerGenerators.genStatus
261+
GreyBoxFuzzerGeneratorsAndSettings.sourceOfRandomness,
262+
GreyBoxFuzzerGeneratorsAndSettings.genStatus
262263
)
263264
} else {
264265
StaticMethodThisInstance

utbot-framework/src/main/kotlin/org/utbot/engine/greyboxfuzzer/generator/DataGenerator.kt

+1-2
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,13 @@ import org.utbot.framework.plugin.api.UtModel
1212
import org.utbot.framework.plugin.api.UtNullModel
1313
import org.utbot.framework.plugin.api.util.id
1414
import org.utbot.framework.plugin.api.util.jClass
15-
import org.utbot.framework.plugin.api.util.objectClassId
1615
import org.utbot.engine.greyboxfuzzer.quickcheck.generator.GenerationState
1716
import org.utbot.engine.greyboxfuzzer.quickcheck.generator.GeneratorContext
1817
import java.lang.reflect.Parameter
1918

2019
object DataGenerator {
2120

22-
private val generatorRepository = GreyBoxFuzzerGenerators.generatorRepository
21+
private val generatorRepository = GreyBoxFuzzerGeneratorsAndSettings.generatorRepository
2322

2423
fun generateUtModel(
2524
parameterTypeContext: ParameterTypeContext,

utbot-framework/src/main/kotlin/org/utbot/engine/greyboxfuzzer/generator/GreyBoxFuzzerGenerators.kt renamed to utbot-framework/src/main/kotlin/org/utbot/engine/greyboxfuzzer/generator/GreyBoxFuzzerGeneratorsAndSettings.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import org.utbot.engine.greyboxfuzzer.quickcheck.random.SourceOfRandomness
1212
import java.util.*
1313
import java.util.concurrent.atomic.AtomicInteger
1414

15-
object GreyBoxFuzzerGenerators {
15+
object GreyBoxFuzzerGeneratorsAndSettings {
1616

1717
const val seed = 42L
1818
val maxDepthOfGeneration = AtomicInteger(5)

utbot-framework/src/main/kotlin/org/utbot/engine/greyboxfuzzer/generator/QuickCheckExtensions.kt

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import org.utbot.engine.greyboxfuzzer.generator.userclasses.UserClassGenerator
1010
import org.utbot.engine.greyboxfuzzer.util.*
1111
import org.utbot.engine.logger
1212
import org.utbot.engine.rawType
13-
import org.utbot.engine.greyboxfuzzer.quickcheck.generator.ComponentizedGenerator
1413
import org.utbot.engine.greyboxfuzzer.quickcheck.generator.Generator
1514
import org.utbot.engine.greyboxfuzzer.quickcheck.generator.GeneratorContext
1615
import org.utbot.engine.greyboxfuzzer.quickcheck.internal.FakeAnnotatedTypeFactory
@@ -87,7 +86,7 @@ fun GeneratorRepository.getOrProduceGenerator(
8786
depth: Int
8887
): Generator? {
8988
val producedUserClassesGenerators = mutableListOf<UserClassGenerator>()
90-
parameterTypeContext.getAllSubParameterTypeContexts(GreyBoxFuzzerGenerators.sourceOfRandomness).reversed()
89+
parameterTypeContext.getAllSubParameterTypeContexts(GreyBoxFuzzerGeneratorsAndSettings.sourceOfRandomness).reversed()
9190
.forEach { typeContext ->
9291
try {
9392
this.produceGenerator(typeContext)

utbot-framework/src/main/kotlin/org/utbot/engine/greyboxfuzzer/generator/userclasses/UserClassGenerator.kt

+9-9
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ class UserClassGenerator : ComponentizedGenerator(Any::class.java) {
6060
if (Random.getTrue(5)) {
6161
return UtNullModel(clazz!!.id)
6262
}
63-
if (depth >= GreyBoxFuzzerGenerators.maxDepthOfGeneration.toInt()) {
64-
logger.debug { "Depth more than maxDepth ${GreyBoxFuzzerGenerators.maxDepthOfGeneration.toInt()}. Return UtNullModel" }
63+
if (depth >= GreyBoxFuzzerGeneratorsAndSettings.maxDepthOfGeneration.toInt()) {
64+
logger.debug { "Depth more than maxDepth ${GreyBoxFuzzerGeneratorsAndSettings.maxDepthOfGeneration.toInt()}. Return UtNullModel" }
6565
return UtNullModel(clazz!!.id)
6666
}
6767
val immutableClazz = clazz!!
@@ -84,7 +84,7 @@ class UserClassGenerator : ComponentizedGenerator(Any::class.java) {
8484
}
8585
val resolvedJavaType = parameterTypeContext!!.generics.resolveType(parameterTypeContext!!.type())
8686
val gctx =
87-
if (resolvedJavaType is Class<*>) {
87+
if (resolvedJavaType is Class<*> && parameterTypeContext!!.generics.genericsInfo.rootClass == immutableClazz) {
8888
parameterTypeContext!!.generics
8989
} else {
9090
resolvedJavaType.createGenericsContext(immutableClazz)
@@ -93,8 +93,8 @@ class UserClassGenerator : ComponentizedGenerator(Any::class.java) {
9393
return InterfaceImplementationsInstanceGenerator(
9494
resolvedJavaType,
9595
gctx,
96-
GreyBoxFuzzerGenerators.sourceOfRandomness,
97-
GreyBoxFuzzerGenerators.genStatus,
96+
GreyBoxFuzzerGeneratorsAndSettings.sourceOfRandomness,
97+
GreyBoxFuzzerGeneratorsAndSettings.genStatus,
9898
generatorContext,
9999
depth
100100
).generate()
@@ -103,8 +103,8 @@ class UserClassGenerator : ComponentizedGenerator(Any::class.java) {
103103
clazz!!,
104104
gctx,
105105
resolvedJavaType,
106-
GreyBoxFuzzerGenerators.sourceOfRandomness,
107-
GreyBoxFuzzerGenerators.genStatus,
106+
GreyBoxFuzzerGeneratorsAndSettings.sourceOfRandomness,
107+
GreyBoxFuzzerGeneratorsAndSettings.genStatus,
108108
generatorContext,
109109
depth
110110
)
@@ -116,8 +116,8 @@ class UserClassGenerator : ComponentizedGenerator(Any::class.java) {
116116
gctx,
117117
parameterTypeContext!!.generics,
118118
generationMethod,
119-
GreyBoxFuzzerGenerators.sourceOfRandomness,
120-
GreyBoxFuzzerGenerators.genStatus,
119+
GreyBoxFuzzerGeneratorsAndSettings.sourceOfRandomness,
120+
GreyBoxFuzzerGeneratorsAndSettings.genStatus,
121121
generatorContext,
122122
depth
123123
).generate()

0 commit comments

Comments
 (0)