Skip to content

Commit 4388b8f

Browse files
committed
Add a series of tests for the concolic execution engine (#8)
* Add a series of tests for the concolic execution engine * Add tests with float to int conversion instructions * Add some additional assertions on the values found + between test for floats * Parameterize floats in between test * Add a few additional tests * Make test more strict (Will fail on an older warduino version) * Give a slightly more informative error message when finding more or less paths * Add CI actions to run the mio setup process and execute the concolic tests * Make checkout in action recursive * Add wabt to dependencies * Update gradle settings to include full stacktrace on failure * Log standard streams for tests * Update symbolic warduino version
1 parent 025fd2f commit 4388b8f

5 files changed

Lines changed: 368 additions & 9 deletions

File tree

.github/workflows/gradle.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ jobs:
1818

1919
steps:
2020
- uses: actions/checkout@v4
21+
with:
22+
submodules: recursive
2123
- name: Set up JDK 22
2224
uses: actions/setup-java@v4
2325
with:
@@ -49,6 +51,15 @@ jobs:
4951
name: MIO fatJar
5052
path: build/libs/mio.jar
5153

54+
- name: Install dependencies
55+
run: sudo apt install -y libz3-dev wabt
56+
57+
- name: Setup MIO
58+
run: ./gradlew setup
59+
60+
- name: Test concolic execution engine
61+
run: ./gradlew test --tests concolic.ConcolicTests
62+
5263
dependency-submission:
5364

5465
runs-on: ubuntu-latest

build.gradle.kts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import java.util.*
22

33
plugins {
4-
kotlin("jvm") version "2.0.0"
4+
kotlin("jvm") version "2.2.0"
55
application
66
}
77

@@ -33,6 +33,12 @@ dependencies {
3333

3434
tasks.test {
3535
useJUnitPlatform()
36+
37+
testLogging {
38+
events("failed")
39+
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
40+
showStandardStreams = true
41+
}
3642
}
3743

3844
kotlin {

src/main/kotlin/be/ugent/topl/mio/concolic/Analyse.kt

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,36 @@ data class SymbolicValueMapping(val primitive: String, val arg: Int, val value:
1414
}
1515
}
1616

17-
data class ConcolicAnalysisResult(val paths: List<SymbolicValueMapping>)
17+
data class ConcolicAnalysisResult(val paths: List<SymbolicValueMapping>) {
18+
fun getPathCount(): Int {
19+
return getPathCount(paths)
20+
}
21+
private fun getPathCount(paths: List<SymbolicValueMapping>): Int {
22+
if (paths.isEmpty()) {
23+
return 1
24+
}
25+
26+
var count = 0
27+
for (path in paths) {
28+
count += getPathCount(path.paths)
29+
}
30+
return count
31+
}
32+
}
1833

19-
fun analyse(wdcliPath: String, wasmFile: String, jsonSnapshot: String, maxInstructions: Int = 50, maxSymbolicVariables: Int = -1, maxIterations: Int = -1, stopPc: Int = -1): ConcolicAnalysisResult {
20-
val woodState = WOODState.fromLine(jsonSnapshot)
21-
val messages = woodState.toBinary(io = false, overrides = false).map { it.trim('\n', ' ') }
22-
for (msg in messages) {
23-
println("\"$msg\"")
34+
fun analyse(wdcliPath: String, wasmFile: String, jsonSnapshot: String?, maxInstructions: Int = 50, maxSymbolicVariables: Int = -1, maxIterations: Int = -1, stopPc: Int = -1): ConcolicAnalysisResult {
35+
val command = if (jsonSnapshot != null) {
36+
val woodState = WOODState.fromLine(jsonSnapshot)
37+
val messages = woodState.toBinary(io = false, overrides = false).map { it.trim('\n', ' ') }
38+
for (msg in messages) {
39+
println("\"$msg\"")
40+
}
41+
listOf(wdcliPath, wasmFile, "--no-socket", "--mode", "concolic", "--snapshot", *messages.toTypedArray(), "end", "--max-instructions", "$maxInstructions", "--max-symbolic-variables", "$maxSymbolicVariables", "--max-iterations", "$maxIterations", "--stop-at-pc", "$stopPc")
42+
}
43+
else {
44+
listOf(wdcliPath, wasmFile, "--no-socket", "--mode", "concolic", "--max-instructions", "$maxInstructions", "--max-symbolic-variables", "$maxSymbolicVariables", "--max-iterations", "$maxIterations", "--stop-at-pc", "$stopPc")
2445
}
2546

26-
val command = listOf(wdcliPath, wasmFile, "--no-socket", "--mode", "concolic", "--snapshot", *messages.toTypedArray(), "end", "--max-instructions", "$maxInstructions", "--max-symbolic-variables", "$maxSymbolicVariables", "--max-iterations", "$maxIterations", "--stop-at-pc", "$stopPc")
2747
println("Running command: ${command.joinToString(" ") }")
2848
val process = ProcessBuilder(command).redirectErrorStream(true).start()
2949
val lineScanner = Scanner(process.inputStream)
@@ -40,6 +60,9 @@ fun analyse(wdcliPath: String, wasmFile: String, jsonSnapshot: String, maxInstru
4060
//process(result)
4161
return ConcolicAnalysisResult(result.paths.sortedBy { it.value })
4262
}
63+
if (currentLine.startsWith("Trap:")) {
64+
throw Exception("Execution resulted in a trap!")
65+
}
4366
}
4467
process.destroy()
4568
println("Output:")

0 commit comments

Comments
 (0)