Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JVM test framework #48

Merged
merged 179 commits into from
Nov 9, 2023
Merged

JVM test framework #48

merged 179 commits into from
Nov 9, 2023

Conversation

DaniilStepanov
Copy link
Collaborator

JVM test framework (work in progress)

This framework is designed to run code and get execution information. The program launch script is specified using a special API

Key Features:

  • Using RD for inter-process communication
  • Coverage in jacodb statements using dynamic instrumentation
  • Descriptors for arguments, used static fields and result
  • Own mock interpreter

TODO's:

  • Fix of the jacodb bug with the translation of IR into JVM bytecode
  • Support java.lang.reflect
  • Sandbox
  • Concolic traces

Comment on lines 45 to 51
data class UTestExecutionSuccessResult(
val trace: List<JcInst>?,
val result: UTestValueDescriptor?,
val initialState: UTestExecutionState,
val resultState: UTestExecutionState
): UTestExecutionResult()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where mocks are stored?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I misunderstood the question.
Mock arguments and instance will be in UTestObjectDescriptor

}

class UTestClassDescriptor(
val classType: JcType, override val type: JcType
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the different between classType and type? Is type a raw type: Class while the classType is Class<Boolean>?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

}
}
classesToReinit.forEach { cl ->
cl.declaredMethods.find { it.name == "generatedClinit0" }?.invoke(null)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is better to introduce named constants

val javaVersionSpecificArguments = OpenModulesContainer.javaVersionSpecificArguments
val instrumentedProcessClassName =
InstrumentedProcess::class.qualifiedName ?: error("Can't find instumented process")
listOf(pathToJava.resolve("bin${File.separatorChar}${osSpecificJavaExecutable()}").toString()) +
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is better to use Paths API to resolve directory instead of File.separatorChar

private fun deserializeTrace(trace: List<Long>, coveredClasses: List<ClassToId>): List<JcInst> =
trace.map { encodedInst ->
deserializedInstructionsCache.getOrPut(encodedInst) {
val classIdOffset = (2.0.pow(Byte.SIZE_BITS * 3).toLong() - 1) shl (Byte.SIZE_BITS * 5 - 1)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is better to move this logic closer with the serializer part

instrumentationProcessRunner.init(lifetime)
} catch (e: Throwable) {
//TODO replace to logger
println("Cant init rdProcess:(")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missed todo

@Test
@Disabled("Jacodb Method Builder issue with instanceOf")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way to bypass this problem and enable tests?

Copy link
Member

@CaelmBleidd CaelmBleidd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looked a bit

}
} catch (e: TimeoutCancellationException) {
val descriptor = UTestExceptionDescriptor(
type = jcClasspath.findClass<Exception>().toType(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you could extract it into into a lazy field? Or better extract it into a method and a variable?

usvm-jvm/src/test/kotlin/org/usvm/util/JcTestExecutor.kt Outdated Show resolved Hide resolved
Comment on lines +221 to +261
val ref = evaluateInModel(heapRef) as UConcreteHeapRef
if (ref.address == NULL_ADDRESS) {
return UTestNullExpression(type) to listOf()
}
// to find a type, we need to understand the source of the object
val typeStream = if (ref.address <= INITIAL_INPUT_ADDRESS) {
// input object
model.typeStreamOf(ref)
} else {
// allocated object
memory.typeStreamOf(ref)
}.filterBySupertype(type)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is a copy of the code from "JcTestExecutor", what is the difference? Can we extract common parts?

val resolvedLength = resolveLValue(lengthRef, ctx.cp.int).first as UTestIntExpression
// TODO hack
val length =
if (resolvedLength.value in 0..10_000) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this constant should be extracted and used in all the places by reference

return resolveLValue(elemRef, type.elementType)
}

//val arrLength = UTestIntExpression(length, ctx.cp.int)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

usvm-jvm/src/test/kotlin/org/usvm/util/JcTestExecutor.kt Outdated Show resolved Hide resolved
Copy link
Member

@CaelmBleidd CaelmBleidd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets make further improvements and fixes in the following requests to make it easier to track and review

@DaniilStepanov DaniilStepanov merged commit 9dc1172 into main Nov 9, 2023
1 check passed
@Saloed Saloed deleted the stepanov/jvm-instrumentation branch December 11, 2023 13:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants