Skip to content

Commit 31d2b8c

Browse files
authored
[TS] Reachability prototype (#308)
1 parent 06624d8 commit 31d2b8c

4 files changed

Lines changed: 125 additions & 1 deletion

File tree

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package org.usvm.api.targets
2+
3+
import org.usvm.machine.state.TsState
4+
import org.usvm.statistics.UMachineObserver
5+
6+
class ReachabilityObserver : UMachineObserver<TsState> {
7+
override fun onState(parent: TsState, forks: Sequence<TsState>) {
8+
parent
9+
.targets
10+
.filter { it is TsReachabilityTarget }
11+
.forEach { target ->
12+
if (target.location == parent.pathNode.parent?.statement) {
13+
target.propagate(parent)
14+
}
15+
}
16+
17+
forks.forEach { fork ->
18+
fork
19+
.targets
20+
.filter { it is TsReachabilityTarget }
21+
.forEach { target ->
22+
if (target.location == fork.pathNode.parent?.statement) {
23+
target.propagate(fork)
24+
}
25+
}
26+
}
27+
}
28+
29+
override fun onStateTerminated(state: TsState, stateReachable: Boolean) {
30+
state.targets
31+
.filter { it is TsReachabilityTarget }
32+
.forEach { target ->
33+
if (target.location == state.pathNode.statement) {
34+
target.propagate(state)
35+
}
36+
}
37+
}
38+
}

usvm-ts/src/main/kotlin/org/usvm/api/targets/TsTarget.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,10 @@ package org.usvm.api.targets
33
import org.jacodb.ets.model.EtsStmt
44
import org.usvm.targets.UTarget
55

6-
class TsTarget : UTarget<EtsStmt, TsTarget>()
6+
open class TsTarget(location: EtsStmt?) : UTarget<EtsStmt, TsTarget>(location)
7+
8+
sealed class TsReachabilityTarget(override val location: EtsStmt) : TsTarget(location) {
9+
class InitialPoint(location: EtsStmt) : TsReachabilityTarget(location)
10+
class IntermediatePoint(location: EtsStmt) : TsReachabilityTarget(location)
11+
class FinalPoint(location: EtsStmt) : TsReachabilityTarget(location)
12+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package org.usvm.checkers
2+
3+
import org.jacodb.ets.model.EtsScene
4+
import org.jacodb.ets.utils.loadEtsFileAutoConvert
5+
import org.usvm.PathSelectionStrategy
6+
import org.usvm.UMachineOptions
7+
import org.usvm.api.targets.ReachabilityObserver
8+
import org.usvm.api.targets.TsReachabilityTarget
9+
import org.usvm.machine.TsMachine
10+
import org.usvm.machine.TsOptions
11+
import org.usvm.util.getResourcePath
12+
import kotlin.test.Test
13+
import kotlin.time.Duration.Companion.seconds
14+
15+
class ReachabilityChecker {
16+
val scene = run {
17+
val name = "ReachabilityChecker.ts"
18+
val path = getResourcePath("/checkers/$name")
19+
val file = loadEtsFileAutoConvert(path)
20+
EtsScene(listOf(file))
21+
}
22+
val options = UMachineOptions(
23+
stopOnTargetsReached = true,
24+
pathSelectionStrategies = listOf(PathSelectionStrategy.TARGETED),
25+
timeout = 15000000.seconds
26+
)
27+
val tsOptions = TsOptions()
28+
29+
@Test
30+
fun runReachabilityCheck() {
31+
val machine = TsMachine(scene, options, tsOptions, machineObserver = ReachabilityObserver())
32+
val method = scene.projectClasses
33+
.flatMap { it.methods }
34+
.single { it.name == "simpleFunction" }
35+
36+
val initialPoint = method.cfg.stmts.first { "if (" in it.toString() }
37+
val initialTarget = TsReachabilityTarget.InitialPoint(initialPoint)
38+
39+
val intermediatePoint = method.cfg.stmts.filter { "if (" in it.toString() }[1]
40+
val intermediateTarget = TsReachabilityTarget.IntermediatePoint(intermediatePoint).also {
41+
initialTarget.addChild((it))
42+
}
43+
val finalPoint = method.cfg.stmts.first { "return" in it.toString() }
44+
TsReachabilityTarget.FinalPoint(finalPoint).also {
45+
intermediateTarget.addChild(it)
46+
}
47+
48+
val results = machine.analyze(listOf(method), listOf(initialTarget))
49+
require(results.size == 1) { "Expected exactly one result, but got ${results.size}" }
50+
}
51+
52+
@Test
53+
fun runReachabilityCheckForFirstInstruction() {
54+
val machine = TsMachine(scene, options, tsOptions, machineObserver = ReachabilityObserver())
55+
val method = scene.projectClasses
56+
.flatMap { it.methods }
57+
.single { it.name == "simpleFunction" }
58+
59+
val initialPoint = method.cfg.stmts.first()
60+
val initialTarget = TsReachabilityTarget.InitialPoint(initialPoint)
61+
62+
val results = machine.analyze(listOf(method), listOf(initialTarget))
63+
require(results.isEmpty()) { "Expected no analysis results, but got ${results.size}" }
64+
require(initialTarget.isRemoved) { "Expected initial target to be removed, but it was not" }
65+
}
66+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
class ReachabilityChecker {
2+
// A target for this function will be 'if(x) -> if (y > 14) -> return 1'
3+
simpleFunction(x: boolean, y: number): number {
4+
if (x) {
5+
if (y > 14) {
6+
return 1;
7+
} else {
8+
return 2;
9+
}
10+
} else {
11+
return 3;
12+
}
13+
}
14+
}

0 commit comments

Comments
 (0)