Skip to content

Commit 1ccd345

Browse files
Fix tree updates iterator (#64)
1 parent 76ddc87 commit 1ccd345

File tree

5 files changed

+55
-20
lines changed

5 files changed

+55
-20
lines changed

usvm-core/src/main/kotlin/org/usvm/memory/SymbolicCollectionUpdates.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ data class UTreeUpdates<Key, Reg : Region<Reg>, Sort : USort>(
337337
) : Iterator<UUpdateNode<Key, Sort>> {
338338
// A set of values we already emitted by this iterator.
339339
// Note that it contains ONLY elements that have duplicates by key in the RegionTree.
340+
// Reference equality on UUpdateNodes is very important here.
340341
private val emittedUpdates = hashSetOf<UUpdateNode<Key, Sort>>()
341342

342343
// We can return just `hasNext` value without checking for duplicates since

usvm-core/src/main/kotlin/org/usvm/memory/UpdateNodes.kt

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,6 @@ class UPinpointUpdateNode<Key, Sort : USort>(
115115
return res
116116
}
117117

118-
override fun equals(other: Any?): Boolean =
119-
other is UPinpointUpdateNode<*, *> && this.key == other.key && this.guard == other.guard
120-
121-
override fun hashCode(): Int = key.hashCode() * 31 + guard.hashCode() // Ignores value
122-
123118
override fun toString(): String = "{$key <- $value}".takeIf { guard.isTrue } ?: "{$key <- $value | $guard}"
124119
}
125120

@@ -204,15 +199,6 @@ class URangedUpdateNode<CollectionId : USymbolicCollectionId<SrcKey, Sort, Colle
204199
return resultUpdateNode
205200
}
206201

207-
// Ignores update
208-
override fun equals(other: Any?): Boolean =
209-
other is URangedUpdateNode<*, *, *, *> &&
210-
this.adapter == other.adapter &&
211-
this.guard == other.guard
212-
213-
// Ignores update
214-
override fun hashCode(): Int = adapter.hashCode() * 31 + guard.hashCode()
215-
216202
/**
217203
* Applies this update node to the [memory] with applying composition via [composer].
218204
*/

usvm-core/src/test/kotlin/org/usvm/CompositionTest.kt

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -363,12 +363,18 @@ internal class CompositionTest {
363363
val sndComposedExpr = sndComposer.compose(fstArrayIndexReading)
364364
val fstComposedExpr = fstComposer.compose(sndComposedExpr)
365365

366-
val expectedRegion = region
367-
.write(USymbolicArrayIndex(fstAddress, fstIndex), 1.toBv(), guard = mkTrue())
368-
.write(USymbolicArrayIndex(sndAddress, sndIndex), 2.toBv(), guard = mkTrue())
369-
370366
require(fstComposedExpr is UInputArrayReading<*, *>)
371-
assert(fstComposedExpr.collection.updates.toList() == expectedRegion.updates.toList())
367+
368+
val updates = fstComposedExpr.collection.updates.toList()
369+
assertEquals(2, updates.size)
370+
val update0 = assertIs<UPinpointUpdateNode<USymbolicArrayIndex, USizeSort>>(updates[0])
371+
val update1 = assertIs<UPinpointUpdateNode<USymbolicArrayIndex, USizeSort>>(updates[1])
372+
373+
assertEquals(update0.key, USymbolicArrayIndex(fstAddress, fstIndex))
374+
assertEquals(update0.value, 1.toBv())
375+
376+
assertEquals(update1.key, USymbolicArrayIndex(sndAddress, sndIndex))
377+
assertEquals(update1.value, 2.toBv())
372378
}
373379

374380
@Test

usvm-core/src/test/kotlin/org/usvm/memory/MemoryRegionTests.kt renamed to usvm-core/src/test/kotlin/org/usvm/memory/MemoryRegionTest.kt

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ import org.usvm.UComponents
1313
import org.usvm.UContext
1414
import org.usvm.UHeapRef
1515
import org.usvm.collection.array.UAllocatedArrayId
16+
import org.usvm.collection.array.UInputArrayId
1617
import org.usvm.regions.SetRegion
1718
import org.usvm.regions.emptyRegionTree
19+
import kotlin.random.Random
1820
import kotlin.test.assertNotNull
1921
import kotlin.test.assertTrue
2022

21-
class MemoryRegionTests {
23+
class MemoryRegionTest {
2224
private lateinit var ctx: UContext
2325

2426
@BeforeEach
@@ -107,4 +109,40 @@ class MemoryRegionTests {
107109
assertTrue(updatesAfter.last().includesConcretely(idx2, trueExpr))
108110
}
109111

112+
/**
113+
* Tests random writes and reads with array region to ensure there are no REs.
114+
*/
115+
@Test
116+
fun testSymbolicWrites(): Unit = with(ctx) {
117+
val random = Random(42)
118+
val range = 3
119+
120+
val concreteRefs = List(range) { mkConcreteHeapRef(it) }
121+
val symbolicRefs = List(range) { mkRegisterReading(it, addressSort) }
122+
val refs = concreteRefs + symbolicRefs
123+
124+
val concreteIndices = List(range) { mkSizeExpr(it) }
125+
val symbolicIndices = List(range) { mkRegisterReading(it, sizeSort) }
126+
val indices = concreteIndices + symbolicIndices
127+
128+
val testsCount = 100
129+
repeat(testsCount) {
130+
var memoryRegion = UInputArrayId(mockk<Type>(), addressSort)
131+
.emptyRegion()
132+
133+
val writesCount = 20
134+
repeat(writesCount) {
135+
val ref = symbolicRefs.random(random)
136+
val idx = indices.random(random)
137+
val value = refs.random(random)
138+
139+
memoryRegion = memoryRegion.write(ref to idx, value, trueExpr)
140+
}
141+
142+
val readRef = symbolicRefs.random(random)
143+
val readIdx = indices.random(random)
144+
145+
memoryRegion.read(readRef to readIdx)
146+
}
147+
}
110148
}

usvm-util/src/main/kotlin/org/usvm/regions/ProductRegion.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,8 @@ data class ProductRegion<X : Region<X>, Y : Region<Y>>(val products: List<Pair<X
122122
}
123123
return ProductRegion(newProducts)
124124
}
125+
126+
override fun toString(): String = products.joinToString(prefix = "{", separator = ", ", postfix = "}") { (a , b) ->
127+
("$a X $b").prependIndent("\t")
128+
}
125129
}

0 commit comments

Comments
 (0)