Skip to content

Write symbolic value at symbolic index #151

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

Merged
merged 19 commits into from
Jul 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
9c374d1
Write symbolic value at symbolic index
Stevengre Jun 23, 2025
abb1cb8
Set Version: 0.1.113
rv-auditor Jun 23, 2025
3763e0b
Update src/kriscv/kdist/riscv-semantics/lemmas/sparse-bytes-simplific…
Stevengre Jun 24, 2025
501ffb9
fix
Stevengre Jun 24, 2025
4903d42
format
Stevengre Jun 24, 2025
273705b
Enhance simplification rules in RISC-V semantics for writeBytes and #…
Stevengre Jun 24, 2025
36f61a0
delete uneccesary side condition
Stevengre Jun 24, 2025
2d3d815
Enhance writeBytes and #WB operations in RISC-V semantics by introduc…
Stevengre Jun 25, 2025
d95f68c
bring ==Int to the require clause for more general cases
Stevengre Jun 25, 2025
57f2421
Refine documentation for #WB operations in RISC-V semantics. Clarify …
Stevengre Jun 26, 2025
7d44f01
Clarify special case handling in #WB operations for RISC-V semantics.…
Stevengre Jun 26, 2025
a9988ce
Add requires clause
Stevengre Jul 3, 2025
b29dce7
Refactor #WB operation rule in RISC-V semantics documentation. Adjust…
Stevengre Jul 7, 2025
9b3d348
remove the require clause.
Stevengre Jul 7, 2025
9d8a051
Enhance RISC-V semantics by adding a `requires` clause to the #WB ope…
Stevengre Jul 8, 2025
58d565a
Refine termination handling in #WB operation rule for RISC-V semantic…
Stevengre Jul 8, 2025
f8f74fd
Refine `requires` clause in store-symbolic-index-value specification …
Stevengre Jul 8, 2025
d8c0ad6
One rule 4 perfect overlap
Stevengre Jul 8, 2025
74eecca
Update comments and `requires` clause in store-symbolic-index-overlap…
Stevengre Jul 8, 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
2 changes: 1 addition & 1 deletion package/version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.112
0.1.113
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "kriscv"
version = "0.1.112"
version = "0.1.113"
description = "K tooling for the RISC-V architecture"
readme = "README.md"
requires-python = "~=3.10"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,51 @@ For symbolic execution, we need to tackle the patterns of `#bytes(B +Bytes _) _`
requires I >=Int lengthBytes(B) [simplification(45), preserves-definedness]
```

## writeBytes

If the write index is concrete, we can directly call `writeBytesBF` or `writeBytesEF`.

```k
rule writeBytes(I, V, NUM, BF:SparseBytesBF) => writeBytesBF(I, V, NUM, BF) [simplification(45), concrete(I)]
rule writeBytes(I, V, NUM, EF:SparseBytesEF) => writeBytesEF(I, V, NUM, EF) [simplification(45), concrete(I)]
```

If the write index is symbolic, we use `#WB` to wrap the write operation. Unlike `writeBytes`, `#WB` contains a boolean value to determine whether the write operation has been completed. `true` means completed, `false` means not completed.

```k
syntax SparseBytes ::= #WB(Bool, Int, Int, Int, SparseBytes) [function, total]
rule #WB(_, I, V, NUM, B:SparseBytes) => writeBytes(I, V, NUM, B) [concrete]
rule writeBytes(I, V, NUM, B:SparseBytes) => #WB(false, I, V, NUM, B) [simplification]
```

**Termination Control**: The boolean flag ensures that symbolic write operations eventually terminate by transitioning from `false` to `true` state, at which point concrete write functions can be applied when the index becomes concrete.

```k
rule #WB(false, I, V, NUM, BF:SparseBytesBF) => #WB(true, I, V, NUM, BF) [simplification]
rule #WB(false, I, V, NUM, EF:SparseBytesEF) => #WB(true, I, V, NUM, EF) [simplification]
rule #WB(true, I, V, NUM, BF:SparseBytesBF) => writeBytesBF(I, V, NUM, BF) [simplification, concrete(I)]
rule #WB(true, I, V, NUM, EF:SparseBytesEF) => writeBytesEF(I, V, NUM, EF) [simplification, concrete(I)]
```

**Reordering for Optimization**: When multiple `#WB` operations are nested, the rules bring incomplete `#WB` operations (with `false` flag) to the terminal position, allowing them to traverse and find all possible merge opportunities.

```k
rule #WB(false, I0, V0, NUM0, #WB(true, I1, V1, NUM1, B:SparseBytes)) => #WB(true, I1, V1, NUM1, #WB(false, I0, V0, NUM0, B))
requires I0 +Int NUM0 <=Int I1 orBool I1 +Int NUM1 <=Int I0 [simplification]
```

The rule below handles a termination edge case: it immediately marks the operation as complete with reduced priority to avoid infinite rewriting cycles.

```k
rule #WB(false, I0, V0, NUM0, #WB(true, I1, V1, NUM1, B:SparseBytes)) => #WB(true, I0, V0, NUM0, #WB(true, I1, V1, NUM1, B)) [simplification(60)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This rule might fire if the one above is not applied for random reasons, for instance SMT solver timeout. However, it will just cut the simplification short so it is sound.

```

**Write Consolidation**: When multiple write operations target the same symbolic index with equal byte counts (`NUM0 == NUM1`), the rules merge them by eliminating the older write operation. When the new write has fewer bytes than the existing one (`NUM1 < NUM0`), the smaller write is also eliminated to maintain simplicity.

```k
rule #WB(false, I0, V0, NUM0, #WB(_, I1, _, NUM1, B:SparseBytes)) => #WB(false, I0, V0, NUM0, B)
requires I0 <=Int I1 andBool I1 +Int NUM1 <=Int I0 +Int NUM0 [simplification(45)]
```

## writeByteBF

Expand Down
4 changes: 2 additions & 2 deletions src/kriscv/kdist/riscv-semantics/sparse-bytes.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ We provide helpers to prepend either data or an empty region to an existing `Spa
| writeBytesEF(Int, Int, Int, SparseBytesEF) [function, total]
| writeBytesBF(Int, Int, Int, SparseBytesBF) [function, total]

rule writeBytes(I, V, NUM, BF:SparseBytesBF) => writeBytesBF(I, V, NUM, BF)
rule writeBytes(I, V, NUM, EF:SparseBytesEF) => writeBytesEF(I, V, NUM, EF)
rule writeBytes(I, V, NUM, BF:SparseBytesBF) => writeBytesBF(I, V, NUM, BF) [concrete]
rule writeBytes(I, V, NUM, EF:SparseBytesEF) => writeBytesEF(I, V, NUM, EF) [concrete]

rule writeBytesEF(I, _, _ , _ ) => .SparseBytes requires I <Int 0 // error case for totality
rule writeBytesEF(I, V, NUM, .SparseBytes) => prependEmpty(I, #bytes(Int2Bytes(NUM, V, LE)) .SparseBytes) requires I >=Int 0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module STORE-SYMBOLIC-INDEX-OVERLAP-COUNTER
imports RISCV

claim [id]:
<instrs> #CHECK_HALT => #HALT </instrs>
<regs>
.Map
</regs>
<pc> 0 </pc>
<mem>
// Perfect overlapping writes - I0's write completely covers I1's write
storeBytes(I0, V1, 2,
storeBytes(I1, V0, 1, #bytes ( b"\x00\x00" ) .SparseBytes))
=>
// Only I0's write remains since it completely covers I1's write
#WB(true, I0, V1, 2, #bytes ( b"\x00\x00" ) .SparseBytes)
</mem>
<haltCond> ADDRESS ( 0 ) </haltCond>
requires // Perfect overlapping case: I1 is completely within I0's write range
I0 <=Int I1 andBool I1 +Int 1 <=Int I0 +Int 2 // I1's write [I1, I1+1) is within I0's write [I0, I0+2)
endmodule
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module STORE-SYMBOLIC-INDEX-PARTIAL-OVERLAP
imports RISCV

claim [id]:
<instrs> #CHECK_HALT => #HALT </instrs>
<regs>
.Map
</regs>
<pc> 0 </pc>
<mem>
// Partial overlapping writes - only part of the writes overlap
storeBytes(I0, V1, 2,
storeBytes(I1, V0, 2, #bytes ( b"\x00\x00\x00\x00" ) .SparseBytes))
=>
// Ordering is preserved
#WB(true, I0, V1, 2,
#WB(true, I1, V0, 2, #bytes ( b"\x00\x00\x00\x00" ) .SparseBytes))
</mem>
<haltCond> ADDRESS ( 0 ) </haltCond>
requires // Partial overlapping case: I0 starts 1 byte after I1, so they overlap by 1 byte
I0 ==Int I1 +Int 1 // I1 writes [I1, I1+2), I0 writes [I1+1, I1+3), overlap at [I1+1, I1+2)
endmodule
33 changes: 33 additions & 0 deletions src/tests/integration/test-data/specs/store-symbolic-index-value.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module STORE-SYMBOLIC-INDEX-VALUE
imports RISCV

claim [id]:
<instrs> #CHECK_HALT => #HALT </instrs>
<regs>
.Map
</regs>
<pc> 0 </pc>
<mem>
storeBytes(0 , V6, 4,
storeBytes(I2, V5, 4,
storeBytes(I1, V4, 2,
storeBytes(I0, V3, 4,
storeBytes(I2, V2, 2,
storeBytes(I1, V1, 4,
storeBytes(I0, V0, 4, #bytes ( b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" ) .SparseBytes)))))))
=> // No way to simplify this without any information about the index. Just eliminate the writes on the same index.
#WB(true, I1, V4, 2,
#WB(true, I1, V1, 4,
#WB(true, I0, V3, 4,
#WB(true, I2, V5, 4,
#bytes (Int2Bytes(4, V6, LE) +Bytes b"\x00\x00\x00\x00\x00\x00\x00\x00") .SparseBytes))))
</mem>
<haltCond> ADDRESS ( 0 ) </haltCond>
requires // Ensure truly non-overlapping writes
// I0 writes 4 bytes [I0, I0+4), must not overlap with [0, 4)
4 <=Int I0 andBool
// I1 writes 4 bytes [I1, I1+4), must not overlap with I0 [I0, I0+4)
I0 +Int 4 <=Int I1 andBool
// I2 writes 4 bytes [I2, I2+4), must not overlap with I1 [I1, I1+4)
I1 +Int 4 <=Int I2
endmodule
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.