Skip to content

Commit a52de85

Browse files
authored
Add support for taint analysis (#65)
1 parent f37c4e6 commit a52de85

43 files changed

Lines changed: 1664 additions & 314 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

usvm-core/src/main/kotlin/org/usvm/Composition.kt

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ open class UComposer<Type>(
2626
) : UExprTransformer<Type>(ctx) {
2727
open fun <Sort : USort> compose(expr: UExpr<Sort>): UExpr<Sort> = apply(expr)
2828

29-
override fun <Sort : USort> transform(expr: USymbol<Sort>): UExpr<Sort> =
30-
error("You must override `transform` function in org.usvm.UComposer for ${expr::class}")
31-
3229
override fun <T : USort> transform(expr: UIteExpr<T>): UExpr<T> =
3330
transformExprAfterTransformed(expr, expr.condition) { condition ->
3431
when {
@@ -42,12 +39,6 @@ open class UComposer<Type>(
4239
expr: URegisterReading<Sort>,
4340
): UExpr<Sort> = with(expr) { memory.stack.readRegister(idx, sort) }
4441

45-
override fun <Sort : USort> transform(expr: UCollectionReading<*, *, *>): UExpr<Sort> =
46-
error("You must override `transform` function in org.usvm.UComposer for ${expr::class}")
47-
48-
override fun <Sort : USort> transform(expr: UMockSymbol<Sort>): UExpr<Sort> =
49-
error("You must override `transform` function in org.usvm.UComposer for ${expr::class}")
50-
5142
override fun <Method, Sort : USort> transform(
5243
expr: UIndexedMethodReturnValue<Method, Sort>,
5344
): UExpr<Sort> = memory.mocker.eval(expr)

usvm-core/src/main/kotlin/org/usvm/Context.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ import org.usvm.collection.set.ref.UInputRefSetWithAllocatedElementsReading
4343
import org.usvm.collection.set.ref.UInputRefSetWithInputElements
4444
import org.usvm.collection.set.ref.UInputRefSetWithInputElementsReading
4545
import org.usvm.memory.splitUHeapRef
46+
import org.usvm.regions.Region
4647
import org.usvm.solver.USolverBase
4748
import org.usvm.types.UTypeSystem
48-
import org.usvm.regions.Region
4949

5050
@Suppress("LeakingThis")
5151
open class UContext(
@@ -67,9 +67,7 @@ open class UContext(
6767
return currentStateId++
6868
}
6969

70-
@Suppress("UNCHECKED_CAST")
71-
fun <Type, Context : UContext> solver(): USolverBase<Type, Context> =
72-
this.solver as USolverBase<Type, Context>
70+
fun <Type> solver(): USolverBase<Type> = this.solver.uncheckedCast()
7371

7472
@Suppress("UNCHECKED_CAST")
7573
fun <Type> typeSystem(): UTypeSystem<Type> =

usvm-core/src/main/kotlin/org/usvm/ExprTransformer.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,8 @@ import org.usvm.collection.set.ref.UInputRefSetWithInputElementsReading
2020
import org.usvm.regions.Region
2121

2222
interface UTransformer<Type> : KTransformer {
23-
fun <Sort : USort> transform(expr: USymbol<Sort>): UExpr<Sort>
24-
2523
fun <Sort : USort> transform(expr: URegisterReading<Sort>): UExpr<Sort>
2624

27-
fun <Sort : USort> transform(expr: UCollectionReading<*, *, *>): UExpr<Sort>
28-
2925
fun <Field, Sort : USort> transform(expr: UInputFieldReading<Field, Sort>): UExpr<Sort>
3026

3127
fun <Sort : USort> transform(expr: UAllocatedArrayReading<Type, Sort>): UExpr<Sort>
@@ -60,8 +56,6 @@ interface UTransformer<Type> : KTransformer {
6056

6157
fun transform(expr: UInputRefSetWithInputElementsReading<Type>): UBoolExpr
6258

63-
fun <Sort : USort> transform(expr: UMockSymbol<Sort>): UExpr<Sort>
64-
6559
fun <Method, Sort : USort> transform(expr: UIndexedMethodReturnValue<Method, Sort>): UExpr<Sort>
6660

6761
fun transform(expr: UIsSubtypeExpr<Type>): UBoolExpr

usvm-core/src/main/kotlin/org/usvm/State.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,21 @@ import org.usvm.model.UModelBase
99
import org.usvm.solver.USatResult
1010
import org.usvm.solver.UUnknownResult
1111
import org.usvm.solver.UUnsatResult
12+
import org.usvm.targets.UTarget
1213

1314
typealias StateId = UInt
1415

1516
abstract class UState<Type, Method, Statement, Context, Target, State>(
1617
// TODO: add interpreter-specific information
17-
ctx: UContext,
18+
val ctx: Context,
1819
open val callStack: UCallStack<Method, Statement>,
19-
open val pathConstraints: UPathConstraints<Type, Context>,
20+
open val pathConstraints: UPathConstraints<Type>,
2021
open val memory: UMemory<Type, Method>,
2122
open var models: List<UModelBase<Type>>,
2223
open var pathLocation: PathsTrieNode<State, Statement>,
2324
targets: List<Target> = emptyList(),
2425
) where Context : UContext,
25-
Target : UTarget<Statement, Target, State>,
26+
Target : UTarget<Statement, Target>,
2627
State : UState<Type, Method, Statement, Context, Target, State> {
2728
/**
2829
* Deterministic state id.
@@ -53,7 +54,7 @@ abstract class UState<Type, Method, Statement, Context, Target, State>(
5354
* Creates new state structurally identical to this.
5455
* If [newConstraints] is null, clones [pathConstraints]. Otherwise, uses [newConstraints] in cloned state.
5556
*/
56-
abstract fun clone(newConstraints: UPathConstraints<Type, Context>? = null): State
57+
abstract fun clone(newConstraints: UPathConstraints<Type>? = null): State
5758

5859
override fun equals(other: Any?): Boolean {
5960
if (this === other) return true
@@ -105,7 +106,7 @@ abstract class UState<Type, Method, Statement, Context, Target, State>(
105106
val previousTargetCount = targetsImpl.size
106107
targetsImpl = targetsImpl.remove(target)
107108

108-
if (previousTargetCount == targetsImpl.size || !target.isRemoved) {
109+
if (previousTargetCount == targetsImpl.size || target.isRemoved) {
109110
return false
110111
}
111112

@@ -155,7 +156,7 @@ private fun <T : UState<Type, *, *, Context, *, T>, Type, Context : UContext> fo
155156
} else {
156157
newConstraintToOriginalState
157158
}
158-
val solver = newConstraintToForkedState.uctx.solver<Type, Context>()
159+
val solver = newConstraintToForkedState.uctx.solver<Type>()
159160
val satResult = solver.checkWithSoftConstraints(constraintsToCheck)
160161

161162
return when (satResult) {
Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
11
package org.usvm
22

3+
import org.usvm.model.ULazyModelDecoder
4+
import org.usvm.model.UModelDecoder
5+
import org.usvm.solver.UExprTranslator
36
import org.usvm.solver.USolverBase
47
import org.usvm.types.UTypeSystem
58

69
/**
710
* Provides core USVM components tuned for specific language.
8-
* Instatiated once per [UContext].
11+
* Instantiated once per [UContext].
912
*/
1013
interface UComponents<Type> {
11-
fun <Context : UContext> mkSolver(ctx: Context): USolverBase<Type, Context>
14+
fun mkSolver(ctx: UContext): USolverBase<Type>
1215
fun mkTypeSystem(ctx: UContext): UTypeSystem<Type>
16+
17+
/**
18+
* Initializes [UExprTranslator] and [UModelDecoder] and returns them. We can safely reuse them while [UContext] is
19+
* alive.
20+
*/
21+
fun buildTranslatorAndLazyDecoder(
22+
ctx: UContext,
23+
): Pair<UExprTranslator<Type>, ULazyModelDecoder<Type>> {
24+
val translator = UExprTranslator<Type>(ctx)
25+
val decoder = ULazyModelDecoder(translator)
26+
27+
return translator to decoder
28+
}
1329
}

usvm-core/src/main/kotlin/org/usvm/constraints/PathConstraints.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import org.usvm.uctx
2121
/**
2222
* Mutable representation of path constraints.
2323
*/
24-
open class UPathConstraints<Type, Context : UContext> private constructor(
25-
val ctx: Context,
24+
open class UPathConstraints<Type> private constructor(
25+
private val ctx: UContext,
2626
logicalConstraints: PersistentSet<UBoolExpr> = persistentSetOf(),
2727
/**
2828
* Specially represented equalities and disequalities between objects, used in various part of constraints management.
@@ -51,7 +51,7 @@ open class UPathConstraints<Type, Context : UContext> private constructor(
5151
var logicalConstraints: PersistentSet<UBoolExpr> = logicalConstraints
5252
private set
5353

54-
constructor(ctx: Context) : this(ctx, persistentSetOf())
54+
constructor(ctx: UContext) : this(ctx, persistentSetOf())
5555

5656
open val isFalse: Boolean
5757
get() = equalityConstraints.isContradicting ||
@@ -128,7 +128,7 @@ open class UPathConstraints<Type, Context : UContext> private constructor(
128128
}
129129
}
130130

131-
open fun clone(): UPathConstraints<Type, Context> {
131+
open fun clone(): UPathConstraints<Type> {
132132
val clonedEqualityConstraints = equalityConstraints.clone()
133133
val clonedTypeConstraints = typeConstraints.clone(clonedEqualityConstraints)
134134
val clonedNumericConstraints = numericConstraints.clone()

usvm-core/src/main/kotlin/org/usvm/model/LazyModelDecoder.kt

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ package org.usvm.model
33
import io.ksmt.expr.KExpr
44
import io.ksmt.solver.KModel
55
import io.ksmt.sort.KUninterpretedSort
6-
import org.usvm.INITIAL_STATIC_ADDRESS
76
import org.usvm.INITIAL_INPUT_ADDRESS
7+
import org.usvm.INITIAL_STATIC_ADDRESS
88
import org.usvm.NULL_ADDRESS
99
import org.usvm.UAddressSort
1010
import org.usvm.UConcreteHeapRef
@@ -19,18 +19,6 @@ interface UModelDecoder<Model> {
1919
fun decode(model: KModel): Model
2020
}
2121

22-
/**
23-
* Initializes [UExprTranslator] and [UModelDecoder] and returns them. We can safely reuse them while [UContext] is
24-
* alive.
25-
*/
26-
fun <Type> buildTranslatorAndLazyDecoder(
27-
ctx: UContext,
28-
): Pair<UExprTranslator<Type>, ULazyModelDecoder<Type>> {
29-
val translator = UExprTranslator<Type>(ctx)
30-
val decoder = ULazyModelDecoder(translator)
31-
32-
return translator to decoder
33-
}
3422

3523
typealias AddressesMapping = Map<UExpr<UAddressSort>, UConcreteHeapRef>
3624

@@ -53,18 +41,18 @@ open class ULazyModelDecoder<Type>(
5341
* equivalence classes of addresses and work with their number in the future.
5442
*/
5543
private fun buildMapping(model: KModel, nullRef: UConcreteHeapRef): AddressesMapping {
56-
val interpreterdNullRef = model.eval(translatedNullRef, isComplete = true)
44+
val interpretedNullRef = model.eval(translatedNullRef, isComplete = true)
5745

5846
val result = mutableMapOf<KExpr<KUninterpretedSort>, UConcreteHeapRef>()
5947
// The null value has the NULL_ADDRESS
60-
result[interpreterdNullRef] = nullRef
48+
result[interpretedNullRef] = nullRef
6149

6250
val universe = model.uninterpretedSortUniverse(ctx.addressSort) ?: return result
6351
// All the numbers are enumerated from the INITIAL_INPUT_ADDRESS to the Int.MIN_VALUE
6452
var counter = INITIAL_INPUT_ADDRESS
6553

6654
for (interpretedAddress in universe) {
67-
if (interpretedAddress == interpreterdNullRef) {
55+
if (interpretedAddress == interpretedNullRef) {
6856
continue
6957
}
7058

usvm-core/src/main/kotlin/org/usvm/ps/PathSelectorFactory.kt

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import org.usvm.PathSelectorCombinationStrategy
55
import org.usvm.UMachineOptions
66
import org.usvm.UPathSelector
77
import org.usvm.UState
8-
import org.usvm.UTarget
98
import org.usvm.algorithms.DeterministicPriorityCollection
109
import org.usvm.algorithms.RandomizedPriorityCollection
1110
import org.usvm.statistics.ApplicationGraph
@@ -17,18 +16,22 @@ import org.usvm.statistics.distances.InterprocDistance
1716
import org.usvm.statistics.distances.InterprocDistanceCalculator
1817
import org.usvm.statistics.distances.MultiTargetDistanceCalculator
1918
import org.usvm.statistics.distances.ReachabilityKind
19+
import org.usvm.targets.UTarget
2020
import org.usvm.util.log2
2121
import kotlin.math.max
2222
import kotlin.random.Random
2323

24-
fun <Method, Statement, Target : UTarget<Statement, Target, State>, State : UState<*, Method, Statement, *, Target, State>> createPathSelector(
24+
fun <Method, Statement, Target, State> createPathSelector(
2525
initialState: State,
2626
options: UMachineOptions,
2727
applicationGraph: ApplicationGraph<Method, Statement>,
2828
coverageStatistics: () -> CoverageStatistics<Method, Statement, State>? = { null },
2929
cfgStatistics: () -> CfgStatistics<Method, Statement>? = { null },
30-
callGraphStatistics: () -> CallGraphStatistics<Method>? = { null }
31-
): UPathSelector<State> {
30+
callGraphStatistics: () -> CallGraphStatistics<Method>? = { null },
31+
): UPathSelector<State>
32+
where Target : UTarget<Statement, Target>,
33+
State : UState<*, Method, Statement, *, Target, State> {
34+
3235
val strategies = options.pathSelectionStrategies
3336
require(strategies.isNotEmpty()) { "At least one path selector strategy should be specified" }
3437

@@ -56,6 +59,7 @@ fun <Method, Statement, Target : UTarget<Statement, Target, State>, State : USta
5659
requireNotNull(cfgStatistics()) { "CFG statistics is required for closest to uncovered path selector" },
5760
applicationGraph
5861
)
62+
5963
PathSelectionStrategy.CLOSEST_TO_UNCOVERED_RANDOM -> createClosestToUncoveredPathSelector(
6064
requireNotNull(coverageStatistics()) { "Coverage statistics is required for closest to uncovered path selector" },
6165
requireNotNull(cfgStatistics()) { "CFG statistics is required for closest to uncovered path selector" },
@@ -68,6 +72,7 @@ fun <Method, Statement, Target : UTarget<Statement, Target, State>, State : USta
6872
requireNotNull(callGraphStatistics()) { "Call graph statistics is required for targeted path selector" },
6973
applicationGraph
7074
)
75+
7176
PathSelectionStrategy.TARGETED_RANDOM -> createTargetedPathSelector<Method, Statement, Target, State>(
7277
requireNotNull(cfgStatistics()) { "CFG statistics is required for targeted path selector" },
7378
requireNotNull(callGraphStatistics()) { "Call graph statistics is required for targeted path selector" },
@@ -79,6 +84,7 @@ fun <Method, Statement, Target : UTarget<Statement, Target, State>, State : USta
7984
requireNotNull(cfgStatistics()) { "CFG statistics is required for targeted call stack local path selector" },
8085
applicationGraph
8186
)
87+
8288
PathSelectionStrategy.TARGETED_CALL_STACK_LOCAL_RANDOM -> createTargetedPathSelector<Method, Statement, Target, State>(
8389
requireNotNull(cfgStatistics()) { "CFG statistics is required for targeted call stack local path selector" },
8490
applicationGraph,
@@ -160,7 +166,12 @@ private fun <Method, Statement, State : UState<*, Method, Statement, *, *, State
160166
applicationGraph
161167
)
162168

163-
coverageStatistics.addOnCoveredObserver { _, method, statement -> distanceCalculator.removeTarget(method, statement) }
169+
coverageStatistics.addOnCoveredObserver { _, method, statement ->
170+
distanceCalculator.removeTarget(
171+
method,
172+
statement
173+
)
174+
}
164175

165176
if (random == null) {
166177
return WeightedPathSelector(
@@ -171,7 +182,12 @@ private fun <Method, Statement, State : UState<*, Method, Statement, *, *, State
171182

172183
return WeightedPathSelector(
173184
priorityCollectionFactory = { RandomizedPriorityCollection(compareById()) { random.nextDouble() } },
174-
weighter = { 1.0 / max(distanceCalculator.calculateDistance(it.currentStatement, it.callStack).toDouble(), 1.0) }
185+
weighter = {
186+
1.0 / max(
187+
distanceCalculator.calculateDistance(it.currentStatement, it.callStack).toDouble(),
188+
1.0
189+
)
190+
}
175191
)
176192
}
177193

@@ -191,11 +207,14 @@ private fun <Method, Statement, State : UState<*, Method, Statement, *, *, State
191207
)
192208
}
193209

194-
internal fun <Method, Statement, Target : UTarget<Statement, Target, State>, State : UState<*, Method, Statement, *, Target, State>> createTargetedPathSelector(
210+
internal fun <Method, Statement, Target, State> createTargetedPathSelector(
195211
cfgStatistics: CfgStatistics<Method, Statement>,
196212
applicationGraph: ApplicationGraph<Method, Statement>,
197213
random: Random? = null,
198-
): UPathSelector<State> {
214+
): UPathSelector<State>
215+
where Target : UTarget<Statement, Target>,
216+
State : UState<*, Method, Statement, *, Target, State> {
217+
199218
val distanceCalculator = MultiTargetDistanceCalculator<Method, Statement, _> { loc ->
200219
CallStackDistanceCalculator(
201220
targets = listOf(loc),
@@ -206,13 +225,14 @@ internal fun <Method, Statement, Target : UTarget<Statement, Target, State>, Sta
206225

207226
fun calculateDistanceToTargets(state: State) =
208227
state.targets.minOfOrNull { target ->
209-
if (target.location == null) {
228+
val location = target.location
229+
if (location == null) {
210230
0u
211231
} else {
212232
distanceCalculator.calculateDistance(
213233
state.currentStatement,
214234
state.callStack,
215-
target.location
235+
location
216236
)
217237
}
218238
} ?: UInt.MAX_VALUE
@@ -249,12 +269,15 @@ private fun InterprocDistance.logWeight(): UInt {
249269
return weight
250270
}
251271

252-
internal fun <Method, Statement, Target : UTarget<Statement, Target, State>, State : UState<*, Method, Statement, *, Target, State>> createTargetedPathSelector(
272+
internal fun <Method, Statement, Target, State> createTargetedPathSelector(
253273
cfgStatistics: CfgStatistics<Method, Statement>,
254274
callGraphStatistics: CallGraphStatistics<Method>,
255275
applicationGraph: ApplicationGraph<Method, Statement>,
256276
random: Random? = null,
257-
): UPathSelector<State> {
277+
): UPathSelector<State>
278+
where Target : UTarget<Statement, Target>,
279+
State : UState<*, Method, Statement, *, Target, State> {
280+
258281
val distanceCalculator = MultiTargetDistanceCalculator<Method, Statement, _> { stmt ->
259282
InterprocDistanceCalculator(
260283
targetLocation = stmt,
@@ -266,13 +289,14 @@ internal fun <Method, Statement, Target : UTarget<Statement, Target, State>, Sta
266289

267290
fun calculateWeight(state: State) =
268291
state.targets.minOfOrNull { target ->
269-
if (target.location == null) {
292+
val location = target.location
293+
if (location == null) {
270294
0u
271295
} else {
272296
distanceCalculator.calculateDistance(
273297
state.currentStatement,
274298
state.callStack,
275-
target.location
299+
location
276300
).logWeight()
277301
}
278302
} ?: UInt.MAX_VALUE

0 commit comments

Comments
 (0)