Skip to content

Commit

Permalink
Configurable size sort (#71)
Browse files Browse the repository at this point in the history
  • Loading branch information
Damtev authored Sep 29, 2023
1 parent 103191f commit a453cbc
Show file tree
Hide file tree
Showing 105 changed files with 1,239 additions and 1,017 deletions.
16 changes: 8 additions & 8 deletions usvm-core/src/main/kotlin/org/usvm/Composition.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ import org.usvm.memory.USymbolicCollectionId
import org.usvm.regions.Region

@Suppress("MemberVisibilityCanBePrivate")
open class UComposer<Type>(
ctx: UContext,
open class UComposer<Type, USizeSort : USort>(
ctx: UContext<USizeSort>,
internal val memory: UReadOnlyMemory<Type>
) : UExprTransformer<Type>(ctx) {
) : UExprTransformer<Type, USizeSort>(ctx) {
open fun <Sort : USort> compose(expr: UExpr<Sort>): UExpr<Sort> = apply(expr)

override fun <T : USort> transform(expr: UIteExpr<T>): UExpr<T> =
Expand Down Expand Up @@ -61,13 +61,13 @@ open class UComposer<Type>(
return collection.read(mappedKey, this@UComposer)
}

override fun transform(expr: UInputArrayLengthReading<Type>): USizeExpr =
override fun transform(expr: UInputArrayLengthReading<Type, USizeSort>): UExpr<USizeSort> =
transformCollectionReading(expr, expr.address)

override fun <Sort : USort> transform(expr: UInputArrayReading<Type, Sort>): UExpr<Sort> =
override fun <Sort : USort> transform(expr: UInputArrayReading<Type, Sort, USizeSort>): UExpr<Sort> =
transformCollectionReading(expr, expr.address to expr.index)

override fun <Sort : USort> transform(expr: UAllocatedArrayReading<Type, Sort>): UExpr<Sort> =
override fun <Sort : USort> transform(expr: UAllocatedArrayReading<Type, Sort, USizeSort>): UExpr<Sort> =
transformCollectionReading(expr, expr.index)

override fun <Field, Sort : USort> transform(expr: UInputFieldReading<Field, Sort>): UExpr<Sort> =
Expand All @@ -93,7 +93,7 @@ open class UComposer<Type>(
expr: UInputRefMapWithInputKeysReading<Type, Sort>
): UExpr<Sort> = transformCollectionReading(expr, expr.mapRef to expr.keyRef)

override fun transform(expr: UInputMapLengthReading<Type>): USizeExpr =
override fun transform(expr: UInputMapLengthReading<Type, USizeSort>): UExpr<USizeSort> =
transformCollectionReading(expr, expr.address)

override fun <ElemSort : USort, Reg : Region<Reg>> transform(
Expand All @@ -119,4 +119,4 @@ open class UComposer<Type>(
}

@Suppress("NOTHING_TO_INLINE")
inline fun <T : USort> UComposer<*>?.compose(expr: UExpr<T>) = this?.apply(expr) ?: expr
inline fun <T : USort> UComposer<*, *>?.compose(expr: UExpr<T>) = this?.apply(expr) ?: expr
65 changes: 42 additions & 23 deletions usvm-core/src/main/kotlin/org/usvm/Context.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,16 @@ import org.usvm.solver.USolverBase
import org.usvm.types.UTypeSystem

@Suppress("LeakingThis")
open class UContext(
components: UComponents<*>,
open class UContext<USizeSort : USort>(
components: UComponents<*, USizeSort>,
operationMode: OperationMode = OperationMode.CONCURRENT,
astManagementMode: AstManagementMode = AstManagementMode.GC,
simplificationMode: SimplificationMode = SimplificationMode.SIMPLIFY,
) : KContext(operationMode, astManagementMode, simplificationMode) {

private val solver by lazy { components.mkSolver(this) }
private val typeSystem by lazy { components.mkTypeSystem(this) }
val sizeExprs by lazy { components.mkSizeExprProvider(this) }

private var currentStateId = 0u

Expand All @@ -74,10 +75,6 @@ open class UContext(
this.typeSystem as UTypeSystem<Type>

val addressSort: UAddressSort = mkUninterpretedSort("Address")
val sizeSort: USizeSort = bv32Sort

fun mkSizeExpr(size: Int): USizeExpr = mkBv(size)

val nullRef: UNullRef = UNullRef(this)

fun mkNullRef(): USymbolicHeapRef {
Expand Down Expand Up @@ -179,31 +176,31 @@ open class UContext(
UInputFieldReading(this, region, address)
}.cast()

private val allocatedArrayReadingCache = mkAstInterner<UAllocatedArrayReading<*, out USort>>()
private val allocatedArrayReadingCache = mkAstInterner<UAllocatedArrayReading<*, out USort, USizeSort>>()

fun <ArrayType, Sort : USort> mkAllocatedArrayReading(
region: UAllocatedArray<ArrayType, Sort>,
index: USizeExpr,
): UAllocatedArrayReading<ArrayType, Sort> = allocatedArrayReadingCache.createIfContextActive {
region: UAllocatedArray<ArrayType, Sort, USizeSort>,
index: UExpr<USizeSort>,
): UAllocatedArrayReading<ArrayType, Sort, USizeSort> = allocatedArrayReadingCache.createIfContextActive {
UAllocatedArrayReading(this, region, index)
}.cast()

private val inputArrayReadingCache = mkAstInterner<UInputArrayReading<*, out USort>>()
private val inputArrayReadingCache = mkAstInterner<UInputArrayReading<*, out USort, USizeSort>>()

fun <ArrayType, Sort : USort> mkInputArrayReading(
region: UInputArray<ArrayType, Sort>,
region: UInputArray<ArrayType, Sort, USizeSort>,
address: UHeapRef,
index: USizeExpr,
): UInputArrayReading<ArrayType, Sort> = inputArrayReadingCache.createIfContextActive {
index: UExpr<USizeSort>,
): UInputArrayReading<ArrayType, Sort, USizeSort> = inputArrayReadingCache.createIfContextActive {
UInputArrayReading(this, region, address, index)
}.cast()

private val inputArrayLengthReadingCache = mkAstInterner<UInputArrayLengthReading<*>>()
private val inputArrayLengthReadingCache = mkAstInterner<UInputArrayLengthReading<*, USizeSort>>()

fun <ArrayType> mkInputArrayLengthReading(
region: UInputArrayLengths<ArrayType>,
region: UInputArrayLengths<ArrayType, USizeSort>,
address: UHeapRef,
): UInputArrayLengthReading<ArrayType> = inputArrayLengthReadingCache.createIfContextActive {
): UInputArrayLengthReading<ArrayType, USizeSort> = inputArrayLengthReadingCache.createIfContextActive {
UInputArrayLengthReading(this, region, address)
}.cast()

Expand Down Expand Up @@ -262,14 +259,14 @@ open class UContext(
UInputRefMapWithInputKeysReading(this, region, mapRef, keyRef)
}.cast()

private val inputSymbolicMapLengthReadingCache = mkAstInterner<UInputMapLengthReading<*>>()
private val inputSymbolicMapLengthReadingCache = mkAstInterner<UInputMapLengthReading<*, USizeSort>>()

fun <MapType> mkInputMapLengthReading(
region: UInputMapLengthCollection<MapType>,
region: UInputMapLengthCollection<MapType, USizeSort>,
address: UHeapRef
): UInputMapLengthReading<MapType> =
): UInputMapLengthReading<MapType, USizeSort> =
inputSymbolicMapLengthReadingCache.createIfContextActive {
UInputMapLengthReading<MapType>(this, region, address)
UInputMapLengthReading(this, region, address)
}.cast()


Expand Down Expand Up @@ -371,7 +368,7 @@ open class UContext(

val uValueSampler: KSortVisitor<KExpr<*>> by lazy { mkUValueSampler() }

class UValueSampler(val uctx: UContext) : DefaultValueSampler(uctx) {
class UValueSampler(val uctx: UContext<*>) : DefaultValueSampler(uctx) {
override fun visit(sort: KUninterpretedSort): KExpr<*> =
if (sort == uctx.addressSort) {
uctx.nullRef
Expand All @@ -392,9 +389,31 @@ open class UContext(
}
}

val <USizeSort : USort> UContext<USizeSort>.sizeSort: USizeSort get() = sizeExprs.sizeSort

fun <USizeSort : USort> UContext<USizeSort>.mkSizeExpr(size: Int): UExpr<USizeSort> =
sizeExprs.mkSizeExpr(size)
fun <USizeSort : USort> UContext<USizeSort>.getIntValue(expr: UExpr<USizeSort>): Int? =
sizeExprs.getIntValue(expr)

fun <USizeSort : USort> UContext<USizeSort>.mkSizeSubExpr(lhs: UExpr<USizeSort>, rhs: UExpr<USizeSort>): UExpr<USizeSort> =
sizeExprs.mkSizeSubExpr(lhs, rhs)
fun <USizeSort : USort> UContext<USizeSort>.mkSizeLeExpr(lhs: UExpr<USizeSort>, rhs: UExpr<USizeSort>): UBoolExpr =
sizeExprs.mkSizeLeExpr(lhs, rhs)
fun <USizeSort : USort> UContext<USizeSort>.mkSizeAddExpr(lhs: UExpr<USizeSort>, rhs: UExpr<USizeSort>): UExpr<USizeSort> =
sizeExprs.mkSizeAddExpr(lhs, rhs)
fun <USizeSort : USort> UContext<USizeSort>.mkSizeGtExpr(lhs: UExpr<USizeSort>, rhs: UExpr<USizeSort>): UBoolExpr =
sizeExprs.mkSizeGtExpr(lhs, rhs)
fun <USizeSort : USort> UContext<USizeSort>.mkSizeGeExpr(lhs: UExpr<USizeSort>, rhs: UExpr<USizeSort>): UBoolExpr =
sizeExprs.mkSizeGeExpr(lhs, rhs)
fun <USizeSort : USort> UContext<USizeSort>.mkSizeLtExpr(lhs: UExpr<USizeSort>, rhs: UExpr<USizeSort>): UBoolExpr =
sizeExprs.mkSizeLtExpr(lhs, rhs)

fun <T : KSort> T.sampleUValue(): KExpr<T> =
accept(uctx.uValueSampler).asExpr(this)

val KAst.uctx
get() = ctx as UContext
get() = ctx as UContext<*>

fun <USizeSort : USort> UContext<*>.withSizeSort(): UContext<USizeSort> = cast()
inline fun <USizeSort : USort, R> UContext<*>.withSizeSort(block: UContext<USizeSort>.() -> R): R = block(withSizeSort())
21 changes: 11 additions & 10 deletions usvm-core/src/main/kotlin/org/usvm/ExprTransformer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ import org.usvm.collection.set.ref.UInputRefSetWithAllocatedElementsReading
import org.usvm.collection.set.ref.UInputRefSetWithInputElementsReading
import org.usvm.regions.Region

interface UTransformer<Type> : KTransformer {
interface UTransformer<Type, USizeSort : USort> : KTransformer {
fun <Sort : USort> transform(expr: URegisterReading<Sort>): UExpr<Sort>

fun <Field, Sort : USort> transform(expr: UInputFieldReading<Field, Sort>): UExpr<Sort>

fun <Sort : USort> transform(expr: UAllocatedArrayReading<Type, Sort>): UExpr<Sort>
fun <Sort : USort> transform(expr: UAllocatedArrayReading<Type, Sort, USizeSort>): UExpr<Sort>

fun <Sort : USort> transform(expr: UInputArrayReading<Type, Sort>): UExpr<Sort>
fun <Sort : USort> transform(expr: UInputArrayReading<Type, Sort, USizeSort>): UExpr<Sort>

fun transform(expr: UInputArrayLengthReading<Type>): USizeExpr
fun transform(expr: UInputArrayLengthReading<Type, USizeSort>): UExpr<USizeSort>

fun <KeySort : USort, Sort : USort, Reg : Region<Reg>> transform(
expr: UAllocatedMapReading<Type, KeySort, Sort, Reg>
Expand All @@ -44,7 +44,7 @@ interface UTransformer<Type> : KTransformer {

fun <Sort : USort> transform(expr: UInputRefMapWithInputKeysReading<Type, Sort>): UExpr<Sort>

fun transform(expr: UInputMapLengthReading<Type>): USizeExpr
fun transform(expr: UInputMapLengthReading<Type, USizeSort>): UExpr<USizeSort>

fun <ElemSort : USort, Reg : Region<Reg>> transform(expr: UAllocatedSetReading<Type, ElemSort, Reg>): UBoolExpr

Expand All @@ -67,12 +67,13 @@ interface UTransformer<Type> : KTransformer {
fun transform(expr: UNullRef): UExpr<UAddressSort>
}

abstract class UExprTransformer<Type>(
ctx: UContext
) : KNonRecursiveTransformer(ctx), UTransformer<Type>
abstract class UExprTransformer<Type, USizeSort : USort>(
ctx: UContext<USizeSort>
) : KNonRecursiveTransformer(ctx), UTransformer<Type, USizeSort>

@Suppress("UNCHECKED_CAST")
fun <Type> UTransformer<*>.asTypedTransformer() = this as UTransformer<Type>
fun <Type, USizeSort : USort> UTransformer<*, *>.asTypedTransformer(): UTransformer<Type, USizeSort> =
this as UTransformer<Type, USizeSort>

@Suppress("NOTHING_TO_INLINE")
inline fun <T : USort> UTransformer<*>?.apply(expr: UExpr<T>) = this?.apply(expr) ?: expr
inline fun <T : USort> UTransformer<*, *>?.apply(expr: UExpr<T>) = this?.apply(expr) ?: expr
40 changes: 19 additions & 21 deletions usvm-core/src/main/kotlin/org/usvm/Expressions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,10 @@ typealias USort = KSort
typealias UBoolSort = KBoolSort
typealias UBvSort = KBvSort
typealias UBv32Sort = KBv32Sort
typealias USizeSort = KBv32Sort
typealias UFpSort = KFpSort

typealias UExpr<Sort> = KExpr<Sort>
typealias UBoolExpr = UExpr<UBoolSort>
typealias USizeExpr = UExpr<USizeSort>
typealias UTrue = KTrue
typealias UFalse = KFalse
typealias UAndExpr = KAndExpr
Expand All @@ -60,7 +58,7 @@ typealias USizeType = Int

//endregion

abstract class USymbol<Sort : USort>(ctx: UContext) : UExpr<Sort>(ctx)
abstract class USymbol<Sort : USort>(ctx: UContext<*>) : UExpr<Sort>(ctx)

//region Object References

Expand Down Expand Up @@ -109,14 +107,14 @@ val UConcreteHeapRef.isAllocated: Boolean get() = address >= INITIAL_CONCRETE_AD
val UConcreteHeapRef.isStatic: Boolean get() = address <= INITIAL_STATIC_ADDRESS

class UConcreteHeapRefDecl internal constructor(
ctx: UContext,
ctx: UContext<*>,
val address: UConcreteHeapAddress,
) : KConstDecl<UAddressSort>(ctx, "0x$address", ctx.addressSort) {
override fun apply(args: List<KExpr<*>>): KApp<UAddressSort, *> = uctx.mkConcreteHeapRef(address)
}

class UConcreteHeapRef internal constructor(
ctx: UContext,
ctx: UContext<*>,
val address: UConcreteHeapAddress,
) : UIntepretedValue<UAddressSort>(ctx) {

Expand All @@ -125,7 +123,7 @@ class UConcreteHeapRef internal constructor(
override val sort: UAddressSort = ctx.addressSort

override fun accept(transformer: KTransformerBase): KExpr<UAddressSort> {
require(transformer is UTransformer<*>) { "Expected a UTransformer, but got: $transformer" }
require(transformer is UTransformer<*, *>) { "Expected a UTransformer, but got: $transformer" }
return transformer.transform(this)
}

Expand All @@ -139,13 +137,13 @@ class UConcreteHeapRef internal constructor(
}

class UNullRef internal constructor(
ctx: UContext,
ctx: UContext<*>,
) : USymbolicHeapRef(ctx) {
override val sort: UAddressSort
get() = uctx.addressSort

override fun accept(transformer: KTransformerBase): KExpr<UAddressSort> {
require(transformer is UTransformer<*>) { "Expected a UTransformer, but got: $transformer" }
require(transformer is UTransformer<*, *>) { "Expected a UTransformer, but got: $transformer" }
return transformer.transform(this)
}

Expand Down Expand Up @@ -193,12 +191,12 @@ const val INITIAL_STATIC_ADDRESS = -(1 shl 20) // Use value not less than UNINTE
//region Read Expressions

class URegisterReading<Sort : USort> internal constructor(
ctx: UContext,
ctx: UContext<*>,
val idx: Int,
override val sort: Sort,
) : USymbol<Sort>(ctx) {
override fun accept(transformer: KTransformerBase): KExpr<Sort> {
require(transformer is UTransformer<*>) { "Expected a UTransformer, but got: $transformer" }
require(transformer is UTransformer<*, *>) { "Expected a UTransformer, but got: $transformer" }
return transformer.transform(this)
}

Expand All @@ -212,7 +210,7 @@ class URegisterReading<Sort : USort> internal constructor(
}

abstract class UCollectionReading<CollectionId : USymbolicCollectionId<Key, Sort, CollectionId>, Key, Sort : USort>(
ctx: UContext,
ctx: UContext<*>,
val collection: USymbolicCollection<CollectionId, Key, Sort>
) : USymbol<Sort>(ctx) {
override val sort: Sort get() = collection.sort
Expand All @@ -222,17 +220,17 @@ abstract class UCollectionReading<CollectionId : USymbolicCollectionId<Key, Sort

//region Mocked Expressions

abstract class UMockSymbol<Sort : USort>(ctx: UContext, override val sort: Sort) : USymbol<Sort>(ctx)
abstract class UMockSymbol<Sort : USort>(ctx: UContext<*>, override val sort: Sort) : USymbol<Sort>(ctx)

// TODO: make indices compositional!
class UIndexedMethodReturnValue<Method, Sort : USort> internal constructor(
ctx: UContext,
ctx: UContext<*>,
val method: Method,
val callIndex: Int,
override val sort: Sort,
) : UMockSymbol<Sort>(ctx, sort) {
override fun accept(transformer: KTransformerBase): KExpr<Sort> {
require(transformer is UTransformer<*>) { "Expected a UTransformer, but got: $transformer" }
require(transformer is UTransformer<*, *>) { "Expected a UTransformer, but got: $transformer" }
return transformer.transform(this)
}

Expand All @@ -250,7 +248,7 @@ class UIndexedMethodReturnValue<Method, Sort : USort> internal constructor(
//region Subtyping Expressions

abstract class UIsExpr<Type> internal constructor(
ctx: UContext,
ctx: UContext<*>,
val ref: UHeapRef,
) : USymbol<UBoolSort>(ctx) {
final override val sort = ctx.boolSort
Expand All @@ -261,13 +259,13 @@ abstract class UIsExpr<Type> internal constructor(
* inheritance is checked only on non-null refs.
*/
class UIsSubtypeExpr<Type> internal constructor(
ctx: UContext,
ctx: UContext<*>,
ref: UHeapRef,
val supertype: Type,
) : UIsExpr<Type>(ctx, ref) {
override fun accept(transformer: KTransformerBase): UBoolExpr {
require(transformer is UTransformer<*>) { "Expected a UTransformer, but got: $transformer" }
return transformer.asTypedTransformer<Type>().transform(this)
require(transformer is UTransformer<*, *>) { "Expected a UTransformer, but got: $transformer" }
return transformer.asTypedTransformer<Type, USort>().transform(this)
}

override fun print(printer: ExpressionPrinter) {
Expand All @@ -284,13 +282,13 @@ class UIsSubtypeExpr<Type> internal constructor(
* inheritance is checked only on non-null refs.
*/
class UIsSupertypeExpr<Type> internal constructor(
ctx: UContext,
ctx: UContext<*>,
ref: UHeapRef,
val subtype: Type,
) : UIsExpr<Type>(ctx, ref) {
override fun accept(transformer: KTransformerBase): UBoolExpr {
require(transformer is UTransformer<*>) { "Expected a UTransformer, but got: $transformer" }
return transformer.asTypedTransformer<Type>().transform(this)
require(transformer is UTransformer<*, *>) { "Expected a UTransformer, but got: $transformer" }
return transformer.asTypedTransformer<Type, USort>().transform(this)
}

override fun print(printer: ExpressionPrinter) {
Expand Down
2 changes: 1 addition & 1 deletion usvm-core/src/main/kotlin/org/usvm/Mocks.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface UMocker<Method> : UMockEvaluator {
}

class UIndexedMocker<Method>(
private val ctx: UContext,
private val ctx: UContext<*>,
private val clauses: PersistentMap<Method, PersistentList<UMockSymbol<out USort>>> = persistentMapOf()
) : UMocker<Method> {
override fun <Sort : USort> call(
Expand Down
Loading

0 comments on commit a453cbc

Please sign in to comment.