Skip to content

Commit 3a42692

Browse files
CaelmBleiddLipen
andauthored
TS type streams (#274)
--------- Co-authored-by: Konstantin Chukharev <lipen00@gmail.com>
1 parent c72b120 commit 3a42692

21 files changed

Lines changed: 639 additions & 212 deletions

File tree

usvm-ts/src/main/kotlin/org/usvm/machine/TsComponents.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import org.usvm.UContext
1212
import org.usvm.UMachineOptions
1313
import org.usvm.USizeExprProvider
1414
import org.usvm.collections.immutable.internal.MutabilityOwnership
15+
import org.usvm.machine.types.TsTypeSystem
1516
import org.usvm.memory.UReadOnlyMemory
1617
import org.usvm.model.ULazyModelDecoder
1718
import org.usvm.solver.UExprTranslator

usvm-ts/src/main/kotlin/org/usvm/machine/TsGraph.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import org.jacodb.ets.model.EtsStmt
66
import org.usvm.dataflow.ts.graph.EtsApplicationGraph
77
import org.usvm.dataflow.ts.graph.EtsApplicationGraphImpl
88
import org.usvm.statistics.ApplicationGraph
9+
import org.usvm.util.EtsHierarchy
910

1011
class TsGraph(scene: EtsScene) : ApplicationGraph<EtsMethod, EtsStmt> {
1112
private val etsGraph: EtsApplicationGraph = EtsApplicationGraphImpl(scene)
13+
val hierarchy: EtsHierarchy = EtsHierarchy(scene)
1214

1315
val cp: EtsScene
1416
get() = etsGraph.cp

usvm-ts/src/main/kotlin/org/usvm/machine/TsMachine.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import org.usvm.api.targets.TsTarget
1212
import org.usvm.machine.interpreter.TsInterpreter
1313
import org.usvm.machine.state.TsMethodResult
1414
import org.usvm.machine.state.TsState
15+
import org.usvm.machine.types.TsTypeSystem
1516
import org.usvm.ps.createPathSelector
1617
import org.usvm.statistics.CompositeUMachineObserver
1718
import org.usvm.statistics.CoverageStatistics
@@ -37,10 +38,10 @@ class TsMachine(
3738
private val machineObserver: UMachineObserver<TsState>? = null,
3839
observer: TsInterpreterObserver? = null,
3940
) : UMachine<TsState>() {
40-
private val typeSystem = TsTypeSystem(scene, typeOperationsTimeout = 1.seconds)
41+
private val graph = TsGraph(scene)
42+
private val typeSystem = TsTypeSystem(scene, typeOperationsTimeout = 1.seconds, graph.hierarchy)
4143
private val components = TsComponents(typeSystem, options)
4244
private val ctx = TsContext(scene, components)
43-
private val graph = TsGraph(scene)
4445
private val interpreter = TsInterpreter(ctx, graph, tsOptions, observer)
4546
private val cfgStatistics = CfgStatisticsImpl(graph)
4647

usvm-ts/src/main/kotlin/org/usvm/machine/TsTypeSystem.kt

Lines changed: 0 additions & 136 deletions
This file was deleted.

usvm-ts/src/main/kotlin/org/usvm/machine/expr/ExprUtil.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ fun TsContext.mkTruthyExpr(
2525
val conjuncts = mutableListOf<ExprWithTypeConstraint<UBoolSort>>()
2626
val possibleType = memory.types.getTypeStream(expr.asExpr(addressSort)).single() as FakeType
2727

28-
scope.assert(possibleType.mkExactlyOneTypeConstraint(this@mkTruthyExpr))
28+
scope.doWithState {
29+
pathConstraints += possibleType.mkExactlyOneTypeConstraint(this@mkTruthyExpr)
30+
}
2931

3032
if (!possibleType.boolTypeExpr.isFalse) {
3133
conjuncts += ExprWithTypeConstraint(

usvm-ts/src/main/kotlin/org/usvm/machine/expr/TsExprResolver.kt

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import org.jacodb.ets.model.EtsBitOrExpr
1515
import org.jacodb.ets.model.EtsBitXorExpr
1616
import org.jacodb.ets.model.EtsBooleanConstant
1717
import org.jacodb.ets.model.EtsCastExpr
18+
import org.jacodb.ets.model.EtsClassSignature
19+
import org.jacodb.ets.model.EtsClassType
1820
import org.jacodb.ets.model.EtsConstant
1921
import org.jacodb.ets.model.EtsDeleteExpr
2022
import org.jacodb.ets.model.EtsDivExpr
@@ -82,6 +84,7 @@ import org.usvm.UHeapRef
8284
import org.usvm.USort
8385
import org.usvm.api.allocateArray
8486
import org.usvm.dataflow.ts.infer.tryGetKnownType
87+
import org.usvm.dataflow.ts.util.type
8588
import org.usvm.isTrue
8689
import org.usvm.machine.TsConcreteMethodCallStmt
8790
import org.usvm.machine.TsContext
@@ -96,9 +99,11 @@ import org.usvm.machine.state.TsState
9699
import org.usvm.machine.state.lastStmt
97100
import org.usvm.machine.state.localsCount
98101
import org.usvm.machine.state.newStmt
102+
import org.usvm.machine.types.AuxiliaryType
99103
import org.usvm.machine.types.mkFakeValue
100104
import org.usvm.memory.ULValue
101105
import org.usvm.sizeSort
106+
import org.usvm.util.isResolved
102107
import org.usvm.util.mkArrayIndexLValue
103108
import org.usvm.util.mkArrayLengthLValue
104109
import org.usvm.util.mkFieldLValue
@@ -167,7 +172,7 @@ class TsExprResolver(
167172
dependency0: EtsEntity,
168173
dependency1: EtsEntity,
169174
block: (UExpr<out USort>, UExpr<out USort>) -> T,
170-
):T? {
175+
): T? {
171176
val result0 = resolve(dependency0) ?: return null
172177
val result1 = resolve(dependency1) ?: return null
173178
return block(result0, result1)
@@ -413,9 +418,11 @@ class TsExprResolver(
413418
error("Not supported $expr")
414419
}
415420

416-
override fun visit(expr: EtsInstanceOfExpr): UExpr<out USort>? {
417-
logger.warn { "visit(${expr::class.simpleName}) is not implemented yet" }
418-
error("Not supported $expr")
421+
override fun visit(expr: EtsInstanceOfExpr): UExpr<out USort>? = with(ctx) {
422+
val arg = resolve(expr.arg)?.asExpr(addressSort) ?: return null
423+
scope.calcOnState {
424+
memory.types.evalIsSubtype(arg, expr.checkType)
425+
}
419426
}
420427

421428
// endregion
@@ -580,20 +587,20 @@ class TsExprResolver(
580587
// region ACCESS
581588

582589
override fun visit(value: EtsArrayAccess): UExpr<out USort>? = with(ctx) {
583-
val instance = resolve(value.array)?.asExpr(ctx.addressSort) ?: return null
584-
val index = resolve(value.index)?.asExpr(ctx.fp64Sort) ?: return null
590+
val array = resolve(value.array)?.asExpr(addressSort) ?: return null
591+
val index = resolve(value.index)?.asExpr(fp64Sort) ?: return null
585592
val bvIndex = mkFpToBvExpr(
586593
roundingMode = fpRoundingModeSortDefaultValue(),
587594
value = index,
588595
bvSize = 32,
589-
isSigned = true
590-
)
596+
isSigned = true,
597+
).asExpr(sizeSort)
591598

592599
val lValue = mkArrayIndexLValue(
593-
addressSort,
594-
instance,
595-
bvIndex.asExpr(ctx.sizeSort),
596-
value.array.type as EtsArrayType
600+
sort = addressSort,
601+
ref = array,
602+
index = bvIndex,
603+
type = value.array.type as EtsArrayType
597604
)
598605
val expr = scope.calcOnState { memory.read(lValue) }
599606

@@ -604,8 +611,8 @@ class TsExprResolver(
604611

605612
private fun checkUndefinedOrNullPropertyRead(instance: UHeapRef) = with(ctx) {
606613
val neqNull = mkAnd(
607-
mkHeapRefEq(instance, ctx.mkUndefinedValue()).not(),
608-
mkHeapRefEq(instance, ctx.mkTsNullValue()).not()
614+
mkHeapRefEq(instance, mkUndefinedValue()).not(),
615+
mkHeapRefEq(instance, mkTsNullValue()).not()
609616
)
610617

611618
scope.fork(
@@ -624,10 +631,25 @@ class TsExprResolver(
624631
instanceRef: UHeapRef,
625632
field: EtsFieldSignature,
626633
): UExpr<out USort>? = with(ctx) {
634+
val resolvedAddr = if (instanceRef.isFakeObject()) instanceRef.extractRef(scope) else instanceRef
635+
scope.doWithState {
636+
pathConstraints += if (field.enclosingClass != EtsClassSignature.UNKNOWN) {
637+
// If we know an enclosing class of the field,
638+
// we can add a type constraint about the instance type.
639+
// Probably, it's redundant since either both class and field
640+
// know exactly their types or none of them.
641+
val type = EtsClassType(field.enclosingClass)
642+
memory.types.evalIsSubtype(resolvedAddr, type)
643+
} else {
644+
// Otherwise, we add a type constraint that every type containing such field is fine
645+
memory.types.evalIsSubtype(resolvedAddr, AuxiliaryType(setOf(field.name)))
646+
}
647+
}
648+
627649
val etsField = resolveEtsField(instance, field)
628650
val sort = typeToSort(etsField.type)
629651

630-
val expr = if (sort == unresolvedSort) {
652+
if (sort == unresolvedSort) {
631653
val boolLValue = mkFieldLValue(boolSort, instanceRef, field)
632654
val fpLValue = mkFieldLValue(fp64Sort, instanceRef, field)
633655
val refLValue = mkFieldLValue(addressSort, instanceRef, field)
@@ -653,13 +675,6 @@ class TsExprResolver(
653675
val lValue = mkFieldLValue(sort, instanceRef, field)
654676
scope.calcOnState { memory.read(lValue) }
655677
}
656-
657-
// TODO: check 'field.type' vs 'etsField.type'
658-
if (assertIsSubtype(expr, field.type)) {
659-
expr
660-
} else {
661-
null
662-
}
663678
}
664679

665680
override fun visit(value: EtsInstanceFieldRef): UExpr<out USort>? = with(ctx) {
@@ -739,8 +754,17 @@ class TsExprResolver(
739754

740755
// region OTHER
741756

742-
override fun visit(expr: EtsNewExpr): UExpr<out USort>? = scope.calcOnState {
743-
memory.allocConcrete(expr.type)
757+
override fun visit(expr: EtsNewExpr): UExpr<out USort>? = with(ctx) {
758+
// Try to resolve the concrete type if possible.
759+
// Otherwise, create an object with UnclearRefType
760+
val resolvedType = if (expr.type.isResolved()) {
761+
scene.projectAndSdkClasses
762+
.singleOrNull { it.name == expr.type.typeName }?.type
763+
?: expr.type
764+
} else {
765+
expr.type
766+
}
767+
scope.calcOnState { memory.allocConcrete(resolvedType) }
744768
}
745769

746770
override fun visit(expr: EtsNewArrayExpr): UExpr<out USort>? = with(ctx) {
@@ -752,10 +776,10 @@ class TsExprResolver(
752776
}
753777

754778
val bvSize = mkFpToBvExpr(
755-
fpRoundingModeSortDefaultValue(),
756-
size.asExpr(fp64Sort),
779+
roundingMode = fpRoundingModeSortDefaultValue(),
780+
value = size.asExpr(fp64Sort),
757781
bvSize = 32,
758-
isSigned = true
782+
isSigned = true,
759783
)
760784

761785
val condition = mkAnd(
@@ -782,11 +806,6 @@ class TsExprResolver(
782806
}
783807

784808
// endregion
785-
786-
// TODO incorrect implementation
787-
private fun assertIsSubtype(expr: UExpr<out USort>, type: EtsType): Boolean {
788-
return true
789-
}
790809
}
791810

792811
class TsSimpleValueResolver(

0 commit comments

Comments
 (0)