Skip to content

Commit c05e83a

Browse files
authored
Fix a wrong regions mapping (#12)
1 parent 3efe985 commit c05e83a

2 files changed

Lines changed: 61 additions & 3 deletions

File tree

usvm-core/src/main/kotlin/org/usvm/MemoryRegions.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,13 @@ data class UMemoryRegion<RegionId : URegionId<Key>, Key, Sort : USort>(
163163
val mappedUpdates = updates.map(regionId.keyMapper(composer), composer)
164164
val mappedDefaultValue = defaultValue?.let { composer.compose(it) }
165165

166-
// If there is no changes after their composition, return unchecked region
167-
if (mappedUpdates === updates && mappedDefaultValue === defaultValue) {
166+
// Note that we cannot use optimization with unchanged mappedUpdates and mappedDefaultValues here
167+
// since in a new region we might have an updated instantiator.
168+
// Therefore, we have to check their reference equality as well.
169+
if (mappedUpdates === updates && mappedDefaultValue === defaultValue && instantiator === this.instantiator) {
168170
return this
169171
}
170172

171-
// Otherwise, construct a new region with mapped values and a new instantiator.
172173
return UMemoryRegion(regionId, sort, mappedUpdates, mappedDefaultValue, instantiator)
173174
}
174175

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

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,63 @@ internal class CompositionTest<Type, Field> {
297297
assert(sndComposedExpression === answer)
298298
}
299299

300+
@Test
301+
fun testComposeSeveralTimes() = with(ctx) {
302+
val fstAddress = mockk<USymbolicHeapRef>()
303+
val fstIndex = mockk<USizeExpr>()
304+
305+
val sndAddress = mockk<USymbolicHeapRef>()
306+
val sndIndex = mockk<USizeExpr>()
307+
308+
val arrayType: KClass<Array<*>> = Array::class
309+
// Create an empty region
310+
val region = emptyInputArrayRegion(arrayType, mkBv32Sort()) { key, memoryRegion ->
311+
mkInputArrayReading(memoryRegion, key.first, key.second)
312+
}
313+
314+
// TODO replace with jacoDB type
315+
// create a reading from the region
316+
val fstArrayIndexReading = mkInputArrayReading(region, fstAddress, fstIndex)
317+
318+
val typeEvaluator = mockk<UTypeEvaluator<KClass<*>>>() // TODO replace with jacoDB type
319+
val sndHeapEvaluator = URegionHeap<Field, KClass<*>>(ctx) // TODO replace with jacoDB type
320+
// create a heap with a record: (sndAddress, sndIndex) = 2
321+
sndHeapEvaluator.writeArrayIndex(sndAddress, sndIndex, arrayType, mkBv32Sort(), 2.toBv(), mkTrue())
322+
323+
val sndComposer = UComposer(
324+
ctx, stackEvaluator, sndHeapEvaluator, typeEvaluator, mockEvaluator
325+
) // TODO replace with jacoDB type
326+
327+
val fstEvaluator = URegionHeap<Field, KClass<*>>(ctx) // TODO replace with jacoDB type
328+
// create a heap with a record: (fstAddress, fstIndex) = 1
329+
fstEvaluator.writeArrayIndex(fstAddress, fstIndex, arrayType, mkBv32Sort(), 1.toBv(), mkTrue())
330+
331+
val fstComposer = UComposer(
332+
ctx, stackEvaluator, fstEvaluator, typeEvaluator, mockEvaluator
333+
) // TODO replace with jacoDB type
334+
335+
// Both heaps leave everything untouched
336+
every { sndAddress.accept(sndComposer) } returns sndAddress
337+
every { sndAddress.accept(fstComposer) } returns sndAddress
338+
every { fstAddress.accept(sndComposer) } returns fstAddress
339+
every { fstAddress.accept(fstComposer) } returns fstAddress
340+
341+
every { fstIndex.accept(fstComposer) } returns fstIndex
342+
every { fstIndex.accept(sndComposer) } returns fstIndex
343+
every { sndIndex.accept(fstComposer) } returns sndIndex
344+
every { sndIndex.accept(sndComposer) } returns sndIndex
345+
346+
val sndComposedExpr = sndComposer.compose(fstArrayIndexReading)
347+
val fstComposedExpr = fstComposer.compose(sndComposedExpr)
348+
349+
val expectedRegion = region
350+
.write(USymbolicArrayIndex(fstAddress, fstIndex), 1.toBv(), guard = mkTrue())
351+
.write(USymbolicArrayIndex(sndAddress, sndIndex), 2.toBv(), guard = mkTrue())
352+
353+
require(fstComposedExpr is UInputArrayReading<*, *>)
354+
assert(fstComposedExpr.region.updates.toList() == expectedRegion.updates.toList())
355+
}
356+
300357
@Test
301358
fun testUAllocatedArrayIndexReading() = with(ctx) {
302359
val arrayType: KClass<Array<*>> = Array::class

0 commit comments

Comments
 (0)