Skip to content

Commit

Permalink
Log failed asserts and forks
Browse files Browse the repository at this point in the history
  • Loading branch information
Saloed committed Feb 14, 2024
1 parent 3b83106 commit 644a9e5
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 10 deletions.
9 changes: 5 additions & 4 deletions usvm-core/src/main/kotlin/org/usvm/StepScope.kt
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class StepScope<T : UState<Type, *, Statement, Context, *, T>, Type, Statement,
*
* NOTE: always sets the [stepScopeState] to the [CANNOT_BE_PROCESSED] value.
*/
fun forkMulti(conditionsWithBlockOnStates: List<Pair<UBoolExpr, T.() -> Unit>>) {
fun forkMulti(conditionsWithBlockOnStates: List<Pair<UBoolExpr, T.() -> Unit>>): Unit? {
check(canProcessFurtherOnCurrentStep)

val conditions = conditionsWithBlockOnStates.map { it.first }
Expand All @@ -120,7 +120,7 @@ class StepScope<T : UState<Type, *, Statement, Context, *, T>, Type, Statement,
stepScopeState = CANNOT_BE_PROCESSED
if (forkedStates.isEmpty()) {
stepScopeState = DEAD
return
return null
}

val firstForkedState = forkedStates.first()
Expand All @@ -130,6 +130,7 @@ class StepScope<T : UState<Type, *, Statement, Context, *, T>, Type, Statement,

// Interpret the first state as original and others as forked
this.forkedStates += forkedStates.subList(1, forkedStates.size)
return Unit
}

fun assert(
Expand Down Expand Up @@ -190,7 +191,7 @@ class StepScope<T : UState<Type, *, Statement, Context, *, T>, Type, Statement,
* [forkMultiWithBlackList] version which doesn't fork to the branches with statements
* banned by underlying [forkBlackList].
*/
fun forkMultiWithBlackList(forkCases: List<ForkCase<T, Statement>>) {
fun forkMultiWithBlackList(forkCases: List<ForkCase<T, Statement>>): Unit? {
check(canProcessFurtherOnCurrentStep)

val filteredConditionsWithBlockOnStates = forkCases
Expand All @@ -203,7 +204,7 @@ class StepScope<T : UState<Type, *, Statement, Context, *, T>, Type, Statement,

if (filteredConditionsWithBlockOnStates.isEmpty()) {
stepScopeState = DEAD
return
return null
}

return forkMulti(filteredConditionsWithBlockOnStates)
Expand Down
3 changes: 2 additions & 1 deletion usvm-core/src/main/kotlin/org/usvm/api/MockApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.usvm.UHeapRef
import org.usvm.USort
import org.usvm.UState
import org.usvm.uctx
import org.usvm.utils.logAssertFailure

// TODO: special mock api for variables

Expand Down Expand Up @@ -39,7 +40,7 @@ private inline fun <Type, Method, State> StepScope<State, Type, *, *>.mockSymbol
mkTypeConstraint(ref)
}

assert(typeConstraint) ?: return null
assert(typeConstraint).logAssertFailure { "Type constraint in mockSymbolicRef" } ?: return null

return ref
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import org.usvm.mkSizeExpr
import org.usvm.mkSizeGeExpr
import org.usvm.mkSizeSubExpr
import org.usvm.sizeSort
import org.usvm.utils.logAssertFailure

object ListCollectionApi {
fun <ListType, USizeSort : USort, Ctx: UContext<USizeSort>> UState<ListType, *, *, Ctx, *, *>.mkSymbolicList(
Expand Down Expand Up @@ -51,7 +52,9 @@ object ListCollectionApi {
with(ctx) {
val boundConstraint = mkSizeGeExpr(length, mkSizeExpr(0))
// List size must be correct regardless of guard
assert(boundConstraint) ?: return null
assert(boundConstraint)
.logAssertFailure { "SymbolicList size correctness constraint" }
?: return null
}
symbolicListRef
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import org.usvm.mkSizeGeExpr
import org.usvm.mkSizeSubExpr
import org.usvm.sizeSort
import org.usvm.uctx
import org.usvm.utils.logAssertFailure

object ObjectMapCollectionApi {
fun <MapType, USizeSort : USort, Ctx: UContext<USizeSort>> UState<MapType, *, *, Ctx, *, *>.mkSymbolicObjectMap(
Expand Down Expand Up @@ -61,7 +62,9 @@ object ObjectMapCollectionApi {
with(ctx) {
val boundConstraint = mkSizeGeExpr(length, mkSizeExpr(0))
// Map size must be correct regardless of guard
assert(boundConstraint) ?: return null
assert(boundConstraint)
.logAssertFailure { "SymbolicMap size correctness constraint" }
?: return null
}
symbolicMapRef
}
Expand Down
9 changes: 9 additions & 0 deletions usvm-core/src/main/kotlin/org/usvm/utils/StateUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.usvm.utils
import org.usvm.UBoolExpr
import org.usvm.UState
import org.usvm.isTrue
import org.usvm.logger
import org.usvm.model.UModelBase
import org.usvm.solver.USatResult
import org.usvm.solver.USolverResult
Expand Down Expand Up @@ -97,3 +98,11 @@ fun <T : UState<Type, *, *, *, *, T>, Type> T.applySoftConstraints() {
}
}
}

inline fun Unit?.onStateDeath(crossinline body: () -> Unit) = apply {
if (this == null) body()
}

inline fun Unit?.logAssertFailure(crossinline message: () -> String) = onStateDeath {
logger.info { "Assert failed: ${message()}" }
}
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ import org.usvm.sizeSort
import org.usvm.util.allocHeapRef
import org.usvm.util.enumValuesField
import org.usvm.util.write
import org.usvm.utils.logAssertFailure

/**
* An expression resolver based on JacoDb 3-address code. A result of resolving is `null`, iff
Expand Down Expand Up @@ -333,7 +334,11 @@ class JcExprResolver(
val lengthRef = UArrayLengthLValue(ref, arrayDescriptor, sizeSort)
val length = scope.calcOnState { memory.read(lengthRef).asExpr(sizeSort) }
assertHardMaxArrayLength(length) ?: return null
scope.assert(mkBvSignedLessOrEqualExpr(mkBv(0), length)) ?: return null

scope.assert(mkBvSignedLessOrEqualExpr(mkBv(0), length))
.logAssertFailure { "JcExprResolver: array length >= 0" }
?: return null

length
}

Expand Down Expand Up @@ -505,7 +510,9 @@ class JcExprResolver(
if (type is JcRefType) {
val heapRef = expr.asExpr(ctx.addressSort)
val isExpr = scope.calcOnState { memory.types.evalIsSubtype(heapRef, type) }
scope.assert(isExpr) ?: return false
scope.assert(isExpr)
.logAssertFailure { "JcExprResolver: subtype constraint ${type.typeName}" }
?: return false
}

return true
Expand Down Expand Up @@ -604,6 +611,7 @@ class JcExprResolver(


scope.assert(invariantsConstraint)
.logAssertFailure { "JcExprResolver: enum correctness constraint" }
}

/**
Expand Down Expand Up @@ -804,6 +812,7 @@ class JcExprResolver(
private fun assertHardMaxArrayLength(length: UExpr<USizeSort>): Unit? = with(ctx) {
val lengthLeThanMaxLength = mkBvSignedLessOrEqualExpr(length, mkBv(hardMaxArrayLength))
scope.assert(lengthLeThanMaxLength)
.logAssertFailure { "JcExprResolver: array length max" }
}

// endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ import org.usvm.types.singleOrNull
import org.usvm.util.name
import org.usvm.util.outerClassInstanceField
import org.usvm.util.write
import org.usvm.utils.logAssertFailure
import org.usvm.utils.onStateDeath

typealias JcStepScope = StepScope<JcState, JcType, JcInst, JcContext>

Expand Down Expand Up @@ -483,7 +485,7 @@ class JcInterpreter(
negStmt,
blockOnTrueState = { newStmt(posStmt) },
blockOnFalseState = { newStmt(negStmt) }
)
).onStateDeath { logger.info { "State death on fork with blacklist" } }
}

private fun visitReturnStmt(scope: JcStepScope, stmt: JcReturnInst) {
Expand Down Expand Up @@ -549,6 +551,7 @@ class JcInterpreter(
)

scope.forkMultiWithBlackList(cases + defaultCase)
.onStateDeath { logger.info { "State death on fork with blacklist" } }
}
}

Expand Down

0 comments on commit 644a9e5

Please sign in to comment.