Skip to content

TS type streams #274

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 50 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
61afb46
Move TsTypeSystem in another package
CaelmBleidd Apr 18, 2025
5904b7b
Introduce AuxiliaryType
CaelmBleidd Apr 18, 2025
5d624a1
Small changes
CaelmBleidd Apr 18, 2025
f2474e3
Copy documentation to TsTypeSystem file
CaelmBleidd Apr 22, 2025
1121ed5
Change hasCommonSubtype for primitive types
CaelmBleidd Apr 22, 2025
a95faf3
Minor changes
CaelmBleidd Apr 22, 2025
d02da22
Stream usages
CaelmBleidd Apr 22, 2025
cce7f33
Stream usages with unique fields
CaelmBleidd Apr 23, 2025
850b2c9
Hierarchy implementation
CaelmBleidd Apr 24, 2025
b5c1be0
Add util function for receiving all fields
CaelmBleidd Apr 25, 2025
ed36c93
Remove primitive types from the TopTypeStream
CaelmBleidd Apr 25, 2025
f24f284
Remove top type stream
CaelmBleidd Apr 28, 2025
7114014
Remove primitive types from the type system
CaelmBleidd Apr 28, 2025
79491f9
Replace any and unknown with object class
CaelmBleidd Apr 29, 2025
ec13f52
Tests fixes
CaelmBleidd Apr 29, 2025
f2a0d33
Add instanceof and fixes
CaelmBleidd Apr 29, 2025
024c579
Minor changes
CaelmBleidd Apr 29, 2025
e759ead
Minor changes
CaelmBleidd Apr 29, 2025
754aa7e
Remove mistakenly added code
CaelmBleidd Apr 29, 2025
c9d6e86
Replace assert with path constraints update
CaelmBleidd Apr 29, 2025
b3a0ce9
Remove redundant hierarchy from the ExprResolver
CaelmBleidd Apr 29, 2025
c5ffcb3
Fixes in TsExprResolver
CaelmBleidd Apr 29, 2025
1fff782
Small fixes in TsInterpreter
CaelmBleidd Apr 29, 2025
ab27095
Resolve arg type in getInitialState
CaelmBleidd Apr 30, 2025
e6429f6
Auxiliary type fixes
CaelmBleidd Apr 30, 2025
e7eb2ec
Optimize imports
CaelmBleidd Apr 30, 2025
cadaf1f
Minor fixes
CaelmBleidd Apr 30, 2025
569bbfa
Minor fixes
CaelmBleidd Apr 30, 2025
5b944ce
Rebase fixes
CaelmBleidd Apr 30, 2025
7aade22
Fixes
CaelmBleidd Apr 30, 2025
25bfb34
Change project availability check function
CaelmBleidd Apr 30, 2025
4114f86
Remove redundant method
CaelmBleidd Apr 30, 2025
c795f89
Optimize imports
CaelmBleidd May 5, 2025
ac26135
Minor updates
CaelmBleidd May 5, 2025
29a69e5
Rename shadowed variable
Lipen May 7, 2025
0a94163
Format
Lipen May 7, 2025
b176f3b
Deterministic typeName
Lipen May 7, 2025
9fccca0
Add toString for AuxiliaryType
Lipen May 7, 2025
e53faef
EOF
Lipen May 7, 2025
169004e
Format
Lipen May 7, 2025
0efcc7a
Format
Lipen May 7, 2025
be61485
Use mapValues
Lipen May 7, 2025
ce11394
Add test with structural equality trick
Lipen May 7, 2025
29b383d
Format
Lipen May 7, 2025
706dec8
Reuse docs from interface
Lipen May 7, 2025
2833ed6
Format test samples
Lipen May 7, 2025
4598ff4
Format
Lipen May 7, 2025
0a229af
Use check
Lipen May 7, 2025
5e53644
Format
Lipen May 7, 2025
41b336b
Format
Lipen May 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions usvm-ts/src/main/kotlin/org/usvm/machine/TsComponents.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import org.usvm.UContext
import org.usvm.UMachineOptions
import org.usvm.USizeExprProvider
import org.usvm.collections.immutable.internal.MutabilityOwnership
import org.usvm.machine.types.TsTypeSystem
import org.usvm.memory.UReadOnlyMemory
import org.usvm.model.ULazyModelDecoder
import org.usvm.solver.UExprTranslator
Expand Down
2 changes: 2 additions & 0 deletions usvm-ts/src/main/kotlin/org/usvm/machine/TsGraph.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import org.jacodb.ets.model.EtsStmt
import org.usvm.dataflow.ts.graph.EtsApplicationGraph
import org.usvm.dataflow.ts.graph.EtsApplicationGraphImpl
import org.usvm.statistics.ApplicationGraph
import org.usvm.util.EtsHierarchy

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

val cp: EtsScene
get() = etsGraph.cp
Expand Down
5 changes: 3 additions & 2 deletions usvm-ts/src/main/kotlin/org/usvm/machine/TsMachine.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import org.usvm.api.targets.TsTarget
import org.usvm.machine.interpreter.TsInterpreter
import org.usvm.machine.state.TsMethodResult
import org.usvm.machine.state.TsState
import org.usvm.machine.types.TsTypeSystem
import org.usvm.ps.createPathSelector
import org.usvm.statistics.CompositeUMachineObserver
import org.usvm.statistics.CoverageStatistics
Expand All @@ -37,10 +38,10 @@ class TsMachine(
private val machineObserver: UMachineObserver<TsState>? = null,
observer: TsInterpreterObserver? = null,
) : UMachine<TsState>() {
private val typeSystem = TsTypeSystem(scene, typeOperationsTimeout = 1.seconds)
private val graph = TsGraph(scene)
private val typeSystem = TsTypeSystem(scene, typeOperationsTimeout = 1.seconds, graph.hierarchy)
private val components = TsComponents(typeSystem, options)
private val ctx = TsContext(scene, components)
private val graph = TsGraph(scene)
private val interpreter = TsInterpreter(ctx, graph, tsOptions, observer)
private val cfgStatistics = CfgStatisticsImpl(graph)

Expand Down
136 changes: 0 additions & 136 deletions usvm-ts/src/main/kotlin/org/usvm/machine/TsTypeSystem.kt

This file was deleted.

4 changes: 3 additions & 1 deletion usvm-ts/src/main/kotlin/org/usvm/machine/expr/ExprUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ fun TsContext.mkTruthyExpr(
val conjuncts = mutableListOf<ExprWithTypeConstraint<UBoolSort>>()
val possibleType = memory.types.getTypeStream(expr.asExpr(addressSort)).single() as FakeType

scope.assert(possibleType.mkExactlyOneTypeConstraint(this@mkTruthyExpr))
scope.doWithState {
pathConstraints += possibleType.mkExactlyOneTypeConstraint(this@mkTruthyExpr)
}

if (!possibleType.boolTypeExpr.isFalse) {
conjuncts += ExprWithTypeConstraint(
Expand Down
82 changes: 50 additions & 32 deletions usvm-ts/src/main/kotlin/org/usvm/machine/expr/TsExprResolver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import org.jacodb.ets.model.EtsBitOrExpr
import org.jacodb.ets.model.EtsBitXorExpr
import org.jacodb.ets.model.EtsBooleanConstant
import org.jacodb.ets.model.EtsCastExpr
import org.jacodb.ets.model.EtsClassType
import org.jacodb.ets.model.EtsConstant
import org.jacodb.ets.model.EtsDeleteExpr
import org.jacodb.ets.model.EtsDivExpr
Expand Down Expand Up @@ -82,6 +83,7 @@ import org.usvm.UHeapRef
import org.usvm.USort
import org.usvm.api.allocateArray
import org.usvm.dataflow.ts.infer.tryGetKnownType
import org.usvm.dataflow.ts.util.type
import org.usvm.isTrue
import org.usvm.machine.TsConcreteMethodCallStmt
import org.usvm.machine.TsContext
Expand All @@ -96,9 +98,11 @@ import org.usvm.machine.state.TsState
import org.usvm.machine.state.lastStmt
import org.usvm.machine.state.localsCount
import org.usvm.machine.state.newStmt
import org.usvm.machine.types.AuxiliaryType
import org.usvm.machine.types.mkFakeValue
import org.usvm.memory.ULValue
import org.usvm.sizeSort
import org.usvm.util.isResolved
import org.usvm.util.mkArrayIndexLValue
import org.usvm.util.mkArrayLengthLValue
import org.usvm.util.mkFieldLValue
Expand Down Expand Up @@ -167,7 +171,7 @@ class TsExprResolver(
dependency0: EtsEntity,
dependency1: EtsEntity,
block: (UExpr<out USort>, UExpr<out USort>) -> T,
):T? {
): T? {
val result0 = resolve(dependency0) ?: return null
val result1 = resolve(dependency1) ?: return null
return block(result0, result1)
Expand Down Expand Up @@ -413,9 +417,11 @@ class TsExprResolver(
error("Not supported $expr")
}

override fun visit(expr: EtsInstanceOfExpr): UExpr<out USort>? {
logger.warn { "visit(${expr::class.simpleName}) is not implemented yet" }
error("Not supported $expr")
override fun visit(expr: EtsInstanceOfExpr): UExpr<out USort>? = with(ctx) {
val arg = resolve(expr.arg)?.asExpr(addressSort) ?: return null
scope.calcOnState {
memory.types.evalIsSubtype(arg, expr.checkType)
}
}

// endregion
Expand Down Expand Up @@ -580,20 +586,20 @@ class TsExprResolver(
// region ACCESS

override fun visit(value: EtsArrayAccess): UExpr<out USort>? = with(ctx) {
val instance = resolve(value.array)?.asExpr(ctx.addressSort) ?: return null
val index = resolve(value.index)?.asExpr(ctx.fp64Sort) ?: return null
val array = resolve(value.array)?.asExpr(addressSort) ?: return null
val index = resolve(value.index)?.asExpr(fp64Sort) ?: return null
val bvIndex = mkFpToBvExpr(
roundingMode = fpRoundingModeSortDefaultValue(),
value = index,
bvSize = 32,
isSigned = true
)
isSigned = true,
).asExpr(sizeSort)

val lValue = mkArrayIndexLValue(
addressSort,
instance,
bvIndex.asExpr(ctx.sizeSort),
value.array.type as EtsArrayType
sort = addressSort,
ref = array,
index = bvIndex,
type = value.array.type as EtsArrayType
)
val expr = scope.calcOnState { memory.read(lValue) }

Expand All @@ -604,8 +610,8 @@ class TsExprResolver(

private fun checkUndefinedOrNullPropertyRead(instance: UHeapRef) = with(ctx) {
val neqNull = mkAnd(
mkHeapRefEq(instance, ctx.mkUndefinedValue()).not(),
mkHeapRefEq(instance, ctx.mkTsNullValue()).not()
mkHeapRefEq(instance, mkUndefinedValue()).not(),
mkHeapRefEq(instance, mkTsNullValue()).not()
)

scope.fork(
Expand All @@ -624,10 +630,25 @@ class TsExprResolver(
instanceRef: UHeapRef,
field: EtsFieldSignature,
): UExpr<out USort>? = with(ctx) {
val resolvedAddr = if (instanceRef.isFakeObject()) instanceRef.extractRef(scope) else instanceRef
scope.doWithState {
pathConstraints += if (field.type.isResolved()) {
// If we know an enclosing class of the field,
// we can add a type constraint about the instance type.
// Probably, it's redundant since either both class and field
// know exactly their types or none of them.
val type = EtsClassType(field.enclosingClass)
memory.types.evalIsSubtype(resolvedAddr, type)
} else {
// Otherwise, we add a type constraint that every type containing such field is fine
memory.types.evalIsSubtype(resolvedAddr, AuxiliaryType(setOf(field.name)))
}
}

val etsField = resolveEtsField(instance, field)
val sort = typeToSort(etsField.type)

val expr = if (sort == unresolvedSort) {
if (sort == unresolvedSort) {
val boolLValue = mkFieldLValue(boolSort, instanceRef, field)
val fpLValue = mkFieldLValue(fp64Sort, instanceRef, field)
val refLValue = mkFieldLValue(addressSort, instanceRef, field)
Expand All @@ -653,13 +674,6 @@ class TsExprResolver(
val lValue = mkFieldLValue(sort, instanceRef, field)
scope.calcOnState { memory.read(lValue) }
}

// TODO: check 'field.type' vs 'etsField.type'
if (assertIsSubtype(expr, field.type)) {
expr
} else {
null
}
}

override fun visit(value: EtsInstanceFieldRef): UExpr<out USort>? = with(ctx) {
Expand Down Expand Up @@ -739,8 +753,17 @@ class TsExprResolver(

// region OTHER

override fun visit(expr: EtsNewExpr): UExpr<out USort>? = scope.calcOnState {
memory.allocConcrete(expr.type)
override fun visit(expr: EtsNewExpr): UExpr<out USort>? = with(ctx) {
// Try to resolve the concrete type if possible.
// Otherwise, create an object with UnclearRefType
val resolvedType = if (expr.type.isResolved()) {
scene.projectAndSdkClasses
.singleOrNull { it.name == expr.type.typeName }?.type
?: expr.type
} else {
expr.type
}
scope.calcOnState { memory.allocConcrete(resolvedType) }
}

override fun visit(expr: EtsNewArrayExpr): UExpr<out USort>? = with(ctx) {
Expand All @@ -752,10 +775,10 @@ class TsExprResolver(
}

val bvSize = mkFpToBvExpr(
fpRoundingModeSortDefaultValue(),
size.asExpr(fp64Sort),
roundingMode = fpRoundingModeSortDefaultValue(),
value = size.asExpr(fp64Sort),
bvSize = 32,
isSigned = true
isSigned = true,
)

val condition = mkAnd(
Expand All @@ -782,11 +805,6 @@ class TsExprResolver(
}

// endregion

// TODO incorrect implementation
private fun assertIsSubtype(expr: UExpr<out USort>, type: EtsType): Boolean {
return true
}
}

class TsSimpleValueResolver(
Expand Down
Loading