11package org.utbot.engine.greyboxfuzzer
22
3+ import kotlinx.coroutines.flow.FlowCollector
4+ import kotlinx.coroutines.flow.flow
35import org.utbot.engine.*
46import org.utbot.engine.greyboxfuzzer.generator.*
57import org.utbot.engine.greyboxfuzzer.mutator.Mutator
@@ -12,8 +14,8 @@ import org.utbot.framework.plugin.api.util.*
1214import org.utbot.framework.util.sootMethod
1315import org.utbot.instrumentation.ConcreteExecutor
1416import org.utbot.engine.greyboxfuzzer.quickcheck.generator.GeneratorContext
17+ import java.lang.reflect.Executable
1518import java.lang.reflect.Field
16- import java.lang.reflect.Method
1719import kotlin.random.Random
1820
1921class 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
0 commit comments