Skip to content

Commit 98ee577

Browse files
UnsafeBasedInstanceGenerator done
1 parent e19f081 commit 98ee577

File tree

7 files changed

+164
-27
lines changed

7 files changed

+164
-27
lines changed

utbot-core/src/main/kotlin/org/utbot/common/KClassUtil.kt

+6-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@ import java.lang.reflect.Method
88
* NOTE: vararg parameters must be passed as an array of the corresponding type.
99
*/
1010
fun Method.invokeCatching(obj: Any?, args: List<Any?>) = try {
11-
val invocation = invoke(obj, *args.toTypedArray())
12-
11+
val invocation =
12+
try {
13+
invoke(obj, *args.toTypedArray())
14+
} catch (e: Throwable) {
15+
null
16+
}
1317
Result.success(invocation)
1418
} catch (e: InvocationTargetException) {
1519
Result.failure<Nothing>(e.targetException)

utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt

+6-1
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,15 @@ object UtSettings : AbstractSettings(
222222
var useFuzzing: Boolean by getBooleanProperty(false)
223223

224224
/**
225-
* Set to true to start grey-box fuzzing
225+
* Set to true to use grey-box fuzzing
226226
*/
227227
var useGreyBoxFuzzing: Boolean by getBooleanProperty(true)
228228

229+
/**
230+
* Set to true to use UtCompositeModels in grey-box fuzzing process
231+
*/
232+
var useCompositeModelsInGreyBoxFuzzing: Boolean by getBooleanProperty(true)
233+
229234
/**
230235
* Set the total attempts to improve coverage by fuzzer.
231236
*/

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

+2-5
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import org.utbot.engine.greyboxfuzzer.quickcheck.generator.GeneratorContext
1515
import java.lang.reflect.Field
1616
import java.lang.reflect.Method
1717
import kotlin.random.Random
18-
import kotlin.system.exitProcess
1918

2019
class GreyBoxFuzzer(
2120
private val pathsToUserClasses: String,
@@ -36,7 +35,6 @@ class GreyBoxFuzzer(
3635
private val timeOfStart = System.currentTimeMillis()
3736
private val percentageOfTimeBudgetToChangeMode = 10
3837

39-
//TODO make it return Sequence<UtExecution>
4038
suspend fun fuzz(): Sequence<UtExecution> {
4139
logger.debug { "Started to fuzz ${methodUnderTest.name}" }
4240
val generatorContext = GeneratorContext()
@@ -55,9 +53,7 @@ class GreyBoxFuzzer(
5553
if (timeRemain < 0 || isMethodCovered()) break
5654
exploitationStage()
5755
}
58-
seeds.getBestSeed()
59-
//UtModelGenerator.reset()
60-
return sequenceOf()
56+
return succeededExecutions.asSequence()
6157
}
6258

6359
private suspend fun explorationStage(
@@ -90,6 +86,7 @@ class GreyBoxFuzzer(
9086
thisInstancesHistory += generateThisInstance(methodUnderTest.classId, generatorContext)
9187
regenerateThis = false
9288
} else if (Random.getTrue(60)) {
89+
logger.debug { "Trying to mutate this instance" }
9390
thisInstancesHistory += Mutator.mutateThisInstance(
9491
thisInstancesHistory.last(),
9592
classFieldsUsedByFunc.toList(),

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

+39-7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import org.utbot.framework.plugin.api.util.fieldClassId
1515
import org.utbot.framework.plugin.api.util.fieldId
1616
import org.utbot.framework.plugin.api.util.id
1717
import org.utbot.engine.greyboxfuzzer.quickcheck.generator.*
18+
import org.utbot.framework.UtSettings
1819
import java.lang.reflect.*
1920
import kotlin.random.Random
2021

@@ -56,13 +57,22 @@ class UserClassGenerator : ComponentizedGenerator(Any::class.java) {
5657

5758
private fun regenerate(random: SourceOfRandomness, status: GenerationStatus): UtModel {
5859
logger.debug { "Trying to generate ${parameterTypeContext!!.resolved}. Current depth: $depth" }
60+
if (Random.getTrue(5)) {
61+
return UtNullModel(clazz!!.id)
62+
}
5963
if (depth >= GreyBoxFuzzerGenerators.maxDepthOfGeneration.toInt()) {
6064
logger.debug { "Depth more than maxDepth ${GreyBoxFuzzerGenerators.maxDepthOfGeneration.toInt()}. Return UtNullModel" }
6165
return UtNullModel(clazz!!.id)
6266
}
6367
val immutableClazz = clazz!!
68+
//TODO make this generators as usual generators
6469
when (immutableClazz) {
65-
Any::class.java -> return ObjectGenerator(parameterTypeContext!!, random, status, generatorContext).generate()
70+
Any::class.java -> return ObjectGenerator(
71+
parameterTypeContext!!,
72+
random,
73+
status,
74+
generatorContext
75+
).generate()
6676
Class::class.java -> return ReflectionClassGenerator(parameterTypeContext!!, generatorContext).generate()
6777
Type::class.java -> return ReflectionTypeGenerator(parameterTypeContext!!, generatorContext).generate()
6878
//TODO implement field generator
@@ -73,7 +83,12 @@ class UserClassGenerator : ComponentizedGenerator(Any::class.java) {
7383
return UtNullModel(immutableClazz.id)
7484
}
7585
val resolvedJavaType = parameterTypeContext!!.generics.resolveType(parameterTypeContext!!.type())
76-
val gctx = resolvedJavaType.createGenericsContext(immutableClazz)
86+
val gctx =
87+
if (resolvedJavaType is Class<*>) {
88+
parameterTypeContext!!.generics
89+
} else {
90+
resolvedJavaType.createGenericsContext(immutableClazz)
91+
}
7792
if (!immutableClazz.canBeInstantiated()) {
7893
return InterfaceImplementationsInstanceGenerator(
7994
resolvedJavaType,
@@ -84,7 +99,19 @@ class UserClassGenerator : ComponentizedGenerator(Any::class.java) {
8499
depth
85100
).generate()
86101
}
87-
return ClassesInstanceGenerator(
102+
val unsafeGenerator = UnsafeBasedInstanceGenerator(
103+
clazz!!,
104+
gctx,
105+
resolvedJavaType,
106+
GreyBoxFuzzerGenerators.sourceOfRandomness,
107+
GreyBoxFuzzerGenerators.genStatus,
108+
generatorContext,
109+
depth
110+
)
111+
if (Random.getTrue(10) && UtSettings.useCompositeModelsInGreyBoxFuzzing) {
112+
return unsafeGenerator.generate()
113+
}
114+
val generatedObject = ClassesInstanceGenerator(
88115
clazz!!,
89116
gctx,
90117
parameterTypeContext!!.generics,
@@ -94,6 +121,10 @@ class UserClassGenerator : ComponentizedGenerator(Any::class.java) {
94121
generatorContext,
95122
depth
96123
).generate()
124+
if (generatedObject is UtNullModel && Random.getTrue(75) && UtSettings.useCompositeModelsInGreyBoxFuzzing) {
125+
return unsafeGenerator.generate()
126+
}
127+
return generatedObject
97128
}
98129

99130
override fun modify(random: SourceOfRandomness, status: GenerationStatus): UtModel {
@@ -152,10 +183,11 @@ class UserClassGenerator : ComponentizedGenerator(Any::class.java) {
152183
clazz!!,
153184
chain.map { it!! }.reversed().drop(1)
154185
) ?: return cachedUtModel
155-
return Mutator.regenerateFieldWithContext(genericsContext, cachedUtModel, randomField, generatorContext)?.let {
156-
mutatedFields[randomField] = it.second
157-
it.first
158-
} ?: cachedUtModel
186+
return Mutator.regenerateFieldWithContext(genericsContext, cachedUtModel, randomField, generatorContext)
187+
?.let {
188+
mutatedFields[randomField] = it.second
189+
it.first
190+
} ?: cachedUtModel
159191
}
160192
}
161193

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package org.utbot.engine.greyboxfuzzer.generator.userclasses.generator
2+
3+
import org.utbot.engine.greyboxfuzzer.generator.DataGenerator
4+
import org.utbot.engine.greyboxfuzzer.generator.QuickCheckExtensions
5+
import org.utbot.engine.greyboxfuzzer.quickcheck.generator.GenerationStatus
6+
import org.utbot.engine.greyboxfuzzer.quickcheck.generator.GeneratorContext
7+
import org.utbot.engine.greyboxfuzzer.quickcheck.internal.ParameterTypeContext
8+
import org.utbot.engine.greyboxfuzzer.quickcheck.random.SourceOfRandomness
9+
import org.utbot.engine.greyboxfuzzer.util.*
10+
import org.utbot.framework.plugin.api.ExecutableId
11+
import org.utbot.framework.plugin.api.UtCompositeModel
12+
import org.utbot.framework.plugin.api.UtModel
13+
import org.utbot.framework.plugin.api.UtNullModel
14+
import org.utbot.framework.plugin.api.util.executableId
15+
import org.utbot.framework.plugin.api.util.fieldId
16+
import org.utbot.framework.plugin.api.util.id
17+
import ru.vyarus.java.generics.resolver.context.GenericsContext
18+
import java.lang.reflect.Modifier
19+
import java.lang.reflect.Type
20+
21+
class UnsafeBasedInstanceGenerator(
22+
private val clazz: Class<*>,
23+
private val typeContext: GenericsContext,
24+
private val resolvedType: Type,
25+
private val sourceOfRandomness: SourceOfRandomness,
26+
private val generationStatus: GenerationStatus,
27+
private val generatorContext: GeneratorContext,
28+
private val depth: Int
29+
) : InstanceGenerator {
30+
override fun generate(): UtModel {
31+
val fields = clazz.getAllDeclaredFields()
32+
.filterNot { it.hasModifiers(Modifier.FINAL, Modifier.STATIC) || it.hasModifiers(Modifier.STATIC) }
33+
val sootClazz = clazz.toSootClass() ?: return UtNullModel(clazz.id)
34+
val constructor = generatorContext.utModelConstructor
35+
val allNeededContexts = fields.map { it.declaringClass }.filter { it != clazz }.toSet()
36+
val chainToGenericsContext = allNeededContexts.map { cl ->
37+
val chain = cl.toSootClass()
38+
?.getImplementersOfWithChain()
39+
?.filter { it.contains(sootClazz) }
40+
?.map { it.dropLastWhile { it != sootClazz } }
41+
?.minByOrNull { it.size }
42+
?.map { it.toJavaClass() }
43+
if (chain == null || chain.any { it == null }) {
44+
null
45+
} else {
46+
cl to QuickCheckExtensions.buildGenericsContextForInterfaceParent(
47+
resolvedType,
48+
clazz,
49+
chain.map { it!! }.reversed().drop(1)
50+
)
51+
}
52+
}
53+
val allChainToGenericsContext = chainToGenericsContext + (clazz to typeContext)
54+
val fieldsMocks = fields
55+
.associateTo(mutableMapOf()) { field ->
56+
val genericsContextForField =
57+
allChainToGenericsContext.find { it!!.first == field.declaringClass }?.second
58+
val fieldType =
59+
if (genericsContextForField != null) {
60+
genericsContextForField.resolveFieldType(field).let {
61+
if (it.toClass() == null) field.type else it
62+
}
63+
} else {
64+
field.type
65+
}
66+
val parameterTypeContext = ParameterTypeContext.forType(fieldType, genericsContextForField)
67+
val generatedUtModelWithReturnType =
68+
try {
69+
DataGenerator.generateUtModel(
70+
parameterTypeContext,
71+
depth,
72+
generatorContext,
73+
sourceOfRandomness,
74+
generationStatus
75+
)
76+
} catch (_: Throwable) {
77+
UtNullModel(fieldType.toClass()!!.id)
78+
}
79+
field.fieldId to generatedUtModelWithReturnType
80+
}
81+
return UtCompositeModel(constructor.computeUnusedIdAndUpdate(), clazz.id, isMock = true, fields = fieldsMocks)
82+
}
83+
84+
85+
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ object Mutator {
125125
generatorContext: GeneratorContext
126126
): ThisInstance {
127127
if (thisInstance !is NormalMethodThisInstance) return thisInstance
128-
val thisInstanceAsUtModel = thisInstance.utModel as UtAssembleModel
128+
val thisInstanceAsUtModel = thisInstance.utModel as? UtAssembleModel ?: return thisInstance
129129
val mutationResult =
130130
regenerateFields(
131131
thisInstance.classId.jClass,
@@ -168,7 +168,7 @@ object Mutator {
168168
}
169169
val callModel =
170170
UtExecutableCallModel(fParameter.utModel as UtReferenceModel, randomMethod, parametersForMethodInvocation)
171-
(originalUtModel as UtAssembleModel).addModification(listOf(callModel))
171+
(originalUtModel as? UtAssembleModel)?.addModification(listOf(callModel))
172172
return FParameter(originalParameter, null, fParameter.utModel, fParameter.generator, fParameter.fields)
173173
}
174174

utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockValueConstructor.kt

+24-10
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class MockValueConstructor(
7979
}
8080

8181
// TODO: JIRA:1379 -- replace UtReferenceModel with Int
82-
private val constructedObjects = HashMap<UtReferenceModel, Any>()
82+
private val constructedObjects = HashMap<UtReferenceModel, Any?>()
8383
private val mockInfo = mutableListOf<MockInfo>()
8484
private var mockTarget: MockTarget? = null
8585
private var mockCounter = 0
@@ -193,7 +193,12 @@ class MockValueConstructor(
193193
check(Reflection.isModifiersAccessible())
194194

195195
val target = mockTarget(fieldModel) {
196-
FieldMockTarget(fieldModel.classId.name, model.classId.name, UtConcreteValue(classInstance), fieldId.name)
196+
FieldMockTarget(
197+
fieldModel.classId.name,
198+
model.classId.name,
199+
UtConcreteValue(classInstance),
200+
fieldId.name
201+
)
197202
}
198203
val value = construct(fieldModel, target).value
199204
val instance = if (Modifier.isStatic(declaredField.modifiers)) null else classInstance
@@ -342,9 +347,10 @@ class MockValueConstructor(
342347
val value = construct(elementModel, null).value
343348
try {
344349
java.lang.reflect.Array.set(instance, i, value)
345-
} catch (iae:IllegalArgumentException) {
350+
} catch (iae: IllegalArgumentException) {
346351
throw IllegalArgumentException(
347-
iae.message + " array: ${instance.javaClass.name}; value: ${value?.javaClass?.name}" , iae
352+
iae.message + " array: ${instance.javaClass.name}; value: ${value?.javaClass?.name}",
353+
iae
348354
)
349355
}
350356
}
@@ -357,15 +363,18 @@ class MockValueConstructor(
357363
/**
358364
* Constructs object with [UtAssembleModel].
359365
*/
360-
private fun constructFromAssembleModel(assembleModel: UtAssembleModel): Any {
366+
private fun constructFromAssembleModel(assembleModel: UtAssembleModel): Any? {
361367
constructedObjects[assembleModel]?.let { return it }
362368

363369
val instantiationExecutableCall = assembleModel.instantiationCall
364370
val result = updateWithExecutableCallModel(instantiationExecutableCall)
365-
checkNotNull(result) {
366-
"Tracked instance can't be null for call ${instantiationExecutableCall.executable} in model $assembleModel"
367-
}
371+
// checkNotNull(result) {
372+
// "Tracked instance can't be null for call ${instantiationExecutableCall.executable} in model $assembleModel"
373+
// }
368374
constructedObjects[assembleModel] = result
375+
if (result == null) {
376+
return null
377+
}
369378

370379
assembleModel.modificationsChain.forEach { statementModel ->
371380
when (statementModel) {
@@ -481,8 +490,13 @@ class MockValueConstructor(
481490
}
482491

483492
private fun ConstructorId.call(args: List<Any?>): Any? =
484-
constructor.runSandbox {
485-
newInstance(*args.toTypedArray())
493+
try {
494+
constructor.runSandbox {
495+
this.isAccessible = true
496+
newInstance(*args.toTypedArray())
497+
}
498+
} catch (e: Throwable) {
499+
null
486500
}
487501

488502
/**

0 commit comments

Comments
 (0)