-
Notifications
You must be signed in to change notification settings - Fork 0
Read symbolic value at symbolic address #152
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
base: master
Are you sure you want to change the base?
Changes from all commits
9c374d1
abb1cb8
3763e0b
501ffb9
4903d42
273705b
36f61a0
2d3d815
d95f68c
eb6eb25
8c9abdd
e3cdbd3
3503ce4
249b061
9001ffa
c27b06b
49f6ae3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
0.1.117 | ||
0.1.118 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,41 @@ For symbolic execution, we need to tackle the patterns of `#bytes(B +Bytes _) _` | |
requires I >=Int lengthBytes(B) [simplification(45), preserves-definedness] | ||
``` | ||
|
||
Simplification rules for pickFront and dropFront operations on symbolic write blocks (#WB) | ||
- Default case: For most symbolic write operations, we can bypass the #WB wrapper and apply pickFront directly to the underlying byte structure | ||
```k | ||
rule pickFront(PICK, #WB(_, I, _, _, B:SparseBytes)) => pickFront(PICK, B) | ||
requires PICK <=Int I | ||
[simplification(45)] | ||
``` | ||
- Special case for zero-indexed writes: When a write starts at position 0, we must combine bytes from both the written value and the remaining underlying structure | ||
```k | ||
rule pickFront(PICK, #WB(_, I, V, NUM, B:SparseBytes)) => Int2Bytes(minInt(PICK, NUM), V, LE) +Bytes pickFront(maxInt(0, PICK -Int NUM), B >>SparseBytes NUM) | ||
requires 0 ==Int I [simplification(40)] | ||
``` | ||
- Front-dropping with symbolic writes: Adjust both the write offset and apply dropFront to the underlying structure to maintain correct relative positioning | ||
```k | ||
rule dropFront(DROP, #WB(FLAG, I, V, NUM, B:SparseBytes)) => #WB(FLAG, I -Int DROP, V, NUM, dropFront(DROP, B)) | ||
[simplification(45)] | ||
``` | ||
|
||
## Right Shift Operations | ||
|
||
The `>>SparseBytes` operator performs a right shift operation on SparseBytes, effectively dropping the first N bytes from the sparse byte structure while maintaining the integer value semantics of the remaining bytes. Unlike `dropFront`, which simply removes N bytes from the beginning, `>>SparseBytes` performs a byte-level right shift that preserves the underlying integer representation of the data. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Can you give an example? E.g., using syntax somewhat freely, given a bytes value
What does
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this is an alias for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, you can understand >>Sparse as being specifically for handling a special case of #WB under pickFront that the previous dropFront simplification rule couldn't handle. And the dropFront simplification rule is indeed correct. |
||
|
||
This is primarily used in `pickFront` operations when we need to extract bytes from a specific offset within the sparse byte structure. | ||
|
||
```k | ||
syntax SparseBytes ::= SparseBytes ">>SparseBytes" Int [function, total] | ||
tothtamas28 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// For concrete sparse bytes, we can directly use dropFront to simplify the operation | ||
rule SBS >>SparseBytes SHIFT => dropFront(SHIFT, SBS) [concrete] | ||
|
||
// Symbolic write case: Adjust the written value by right-shifting and recursively apply to underlying structure | ||
rule #WB(FLAG, I, V, NUM, B:SparseBytes) >>SparseBytes SHIFT => #WB(FLAG, maxInt(0, I -Int SHIFT), V >>Int (SHIFT *Int 8), NUM, B >>SparseBytes SHIFT) | ||
requires SHIFT >=Int 0 [simplification(45), preserves-definedness] | ||
Comment on lines
+64
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there is a similar counterexample here for the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In fact, these two simplifications look analogous on the LHS but differ on the RHS:
If There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Found that the Quick idea to fix this issue:
|
||
``` | ||
|
||
## writeBytes | ||
|
||
If the write index is concrete, we can directly call `writeBytesBF` or `writeBytesEF`. | ||
|
@@ -50,10 +85,11 @@ If the write index is symbolic, we use `#WB` to wrap the write operation. Unlike | |
**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)] | ||
rule #WB(_, I, _, NUM, B:SparseBytes) => B requires I <Int 0 orBool NUM <=Int 0 [simplification(40)] | ||
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. | ||
|
@@ -76,7 +112,7 @@ The rule below handles a termination edge case: it immediately marks the operati | |
requires I0 <=Int I1 andBool I1 +Int NUM1 <=Int I0 +Int NUM0 [simplification(45)] | ||
``` | ||
|
||
## writeByteBF | ||
## writeBytesBF | ||
|
||
To write a byte to a symbolic sparse byte region, we need to: | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
module READ-SYMBOLIC-INDEX-VALUE | ||
imports RISCV | ||
|
||
claim [id]: | ||
<instrs> #CHECK_HALT => #HALT </instrs> | ||
<regs> | ||
// read from #bytes | ||
1 |-> (readBytes(4, 4, | ||
#WB(true, I1, V0, 2, | ||
#WB(true, I1, V1, 4, | ||
#WB(true, I0, V2, 4, | ||
#WB(true, I2, V3, 4, | ||
#bytes (b"\x00\x00\x00\x00" +Bytes Int2Bytes(4, V4, LE) +Bytes b"\x00\x00\x00\x00\x00\x00\x00\x00") .SparseBytes))))) | ||
=> V4) | ||
// read I2 with same number of bytes | ||
2 |-> (readBytes(I2, 4, | ||
#WB(true, I1, V0, 2, | ||
#WB(true, I1, V1, 4, | ||
#WB(true, I0, V2, 4, | ||
#WB(true, I2, V3, 4, | ||
#bytes (Int2Bytes(4, V4, LE) +Bytes b"\x00\x00\x00\x00\x00\x00\x00\x00") .SparseBytes))))) | ||
=> V3) | ||
// read I2 with smaller number of bytes | ||
3 |-> (readBytes(I2, 2, | ||
#WB(true, I1, V0, 2, | ||
#WB(true, I1, V1, 4, | ||
#WB(true, I0, V2, 4, | ||
#WB(true, I2, V3, 4, | ||
#bytes (Int2Bytes(4, V4, LE) +Bytes b"\x00\x00\x00\x00\x00\x00\x00\x00") .SparseBytes))))) | ||
=> V3 &Int 65535) | ||
// DISALLOWED: read with more number of bytes (8 bytes, but only 4 stored) | ||
// read I1 with 2 bytes | ||
4 |-> (readBytes(I1, 2, | ||
#WB(true, I1, V0, 2, | ||
#WB(true, I1, V1, 4, | ||
#WB(true, I0, V2, 4, | ||
#WB(true, I2, V3, 4, | ||
#bytes (Int2Bytes(4, V4, LE) +Bytes b"\x00\x00\x00\x00\x00\x00\x00\x00") .SparseBytes))))) | ||
=> V0) | ||
// read I1 with 4 bytes | ||
5 |-> (readBytes(I1, 4, | ||
#WB(true, I1, V0, 2, | ||
#WB(true, I1, V1, 4, | ||
#WB(true, I0, V2, 4, | ||
#WB(true, I2, V3, 4, | ||
#bytes (Int2Bytes(4, V4, LE) +Bytes b"\x00\x00\x00\x00\x00\x00\x00\x00") .SparseBytes))))) | ||
=> Bytes2Int(Int2Bytes(2, V0, LE) +Bytes Int2Bytes(2, V1 >>Int 16, LE), LE, Unsigned)) | ||
</regs> | ||
<pc> 0 </pc> | ||
<haltCond> ADDRESS ( 0 ) </haltCond> | ||
requires 8 <Int I0 andBool I0 +Int 4 <Int I1 andBool I1 +Int 4 <Int I2 | ||
// values are within range | ||
andBool 0 <=Int V0 andBool V0 <=Int 65535 | ||
andBool 0 <=Int V1 andBool V1 <=Int 4294967295 | ||
andBool 0 <=Int V2 andBool V2 <=Int 4294967295 | ||
andBool 0 <=Int V3 andBool V3 <=Int 4294967295 | ||
andBool 0 <=Int V4 andBool V4 <=Int 4294967295 | ||
endmodule | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider
DROP > I
. In that case,WriteBytes(I -Int DROP, ...)
is.SparseBytes
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WriteBytes
and#WB
have different behaviors.#WB
currently doesn't handleindex < 0
.I'll be adding a rule to
#WB
so thatI < 0
acts as a no-op (only written bytes are kept).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That doesn't seem to be sufficient. Consider a case where
I <Int DROP <Int I +Int NUM
: