Skip to content

Commit 8b9d7bf

Browse files
Fix type solving procedure
1 parent bc5436c commit 8b9d7bf

File tree

2 files changed

+42
-4
lines changed

2 files changed

+42
-4
lines changed

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -307,9 +307,14 @@ class UTypeConstraints<Type>(
307307
var nextRegion = currentRegion.intersect(region) // add [heapRef] to the current region
308308
if (nextRegion.isEmpty) {
309309
// conflict detected, so it's impossible for [potentialConflictingRefs]
310-
// to have the common type with [heapRef], therefore they can't be equal
311-
val disjunct = potentialConflictingRefs.map {
312-
with(it.ctx) { it.neq(heapRef) }
310+
// to have the common type with [heapRef], therefore they can't be equal or
311+
// some of them equals null
312+
val disjunct = mutableListOf<UBoolExpr>()
313+
potentialConflictingRefs.mapTo(disjunct) { ref ->
314+
with(ref.uctx) { ref.neq(heapRef) }
315+
}
316+
potentialConflictingRefs.mapTo(disjunct) { ref ->
317+
with(ref.uctx) { ref.eq(nullRef) }
313318
}
314319
bannedRefEqualities += heapRef.ctx.mkOr(disjunct)
315320

usvm-core/src/test/kotlin/org/usvm/types/TypeSolverTest.kt

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,8 @@ class TypeSolverTest {
180180
val a = ctx.mkRegisterReading(0, addressSort)
181181
val b1 = ctx.mkRegisterReading(1, addressSort)
182182
val b2 = ctx.mkRegisterReading(2, addressSort)
183-
184183
val c = ctx.mkRegisterReading(3, addressSort)
184+
185185
pc += mkHeapRefEq(a, nullRef).not() and
186186
mkHeapRefEq(b1, nullRef).not() and
187187
mkHeapRefEq(b2, nullRef).not() and
@@ -226,6 +226,39 @@ class TypeSolverTest {
226226
}
227227
}
228228

229+
@Test
230+
fun `Test symbolic ref -- expressions to assert correctness about null`(): Unit = with(ctx) {
231+
val a = ctx.mkRegisterReading(0, addressSort)
232+
val b = ctx.mkRegisterReading(1, addressSort)
233+
val c = ctx.mkRegisterReading(2, addressSort)
234+
235+
pc += mkIsExpr(a, interfaceAB)
236+
pc += mkIsExpr(b, interfaceBC1)
237+
pc += mkIsExpr(c, interfaceAC)
238+
239+
// it's overcomplicated a == c && b == c
240+
pc += (mkHeapRefEq(a, c) or mkHeapRefEq(b, c)) and (!mkHeapRefEq(a, c) or !mkHeapRefEq(b, c)).not()
241+
242+
val resultBeforeNotNullConstraints = solver.check(pc, useSoftConstraints = false)
243+
val model = assertIs<USatResult<UModelBase<Field, TestType>>>(resultBeforeNotNullConstraints).model
244+
245+
assertIs<USatResult<UModelBase<Field, TestType>>>(resultBeforeNotNullConstraints)
246+
247+
val concreteA = assertIs<UConcreteHeapRef>(model.eval(a)).address
248+
val concreteB = assertIs<UConcreteHeapRef>(model.eval(b)).address
249+
val concreteC = assertIs<UConcreteHeapRef>(model.eval(c)).address
250+
251+
val someIsNull = concreteA == 0 || concreteB == 0 || concreteC == 0
252+
val aEqualsCOrBEqualsC = concreteA == concreteC || concreteB == concreteC
253+
assertTrue(someIsNull && aEqualsCOrBEqualsC)
254+
255+
pc += mkOrNoSimplify(mkHeapRefEq(a, nullRef).not(), falseExpr)
256+
pc += mkOrNoSimplify(mkHeapRefEq(b, nullRef).not(), falseExpr)
257+
258+
val resultWithNotNullConstraints = solver.check(pc, useSoftConstraints = false)
259+
assertIs<UUnsatResult<UModelBase<Field, TestType>>>(resultWithNotNullConstraints)
260+
}
261+
229262
@Test
230263
@Disabled("Support propositional type variables")
231264
fun `Test symbolic ref -- not instance of constraint`(): Unit = with(ctx) {

0 commit comments

Comments
 (0)