Skip to content

Commit 4b3f481

Browse files
authored
Fix offset deref for single elements (#798)
Faulty behaviour when dereferencing pointers after offset was observed in the P-token proofs, returning an array instead of a single element. The quick-fix is to project to a single element during `#derefTruncate` when metadata indicates that a single value is required. Also adds offset tests to `exec_smir` suite. Closes #764
1 parent de63588 commit 4b3f481

22 files changed

+35548
-34
lines changed

kmir/src/kmir/kdist/mir-semantics/kmir.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,16 +165,29 @@ will be `129`.
165165
166166
rule <k> #selectBlock(switchTargets(.Branches, BBIDX), _) => #execBlockIdx(BBIDX) ... </k>
167167
168-
rule <k> #selectBlock(switchTargets(branch(MI, BBIDX) _, _), V) => #execBlockIdx(BBIDX) ... </k> requires #switchMatch(MI, V) [preserves-definedness]
168+
rule <k> #selectBlock(switchTargets(branch(MI, BBIDX) _, _), V) => #execBlockIdx(BBIDX) ... </k>
169+
requires #switchMatch(MI, V)
170+
andBool #switchCanUse(V)
171+
[preserves-definedness]
169172
170-
rule <k> #selectBlock(switchTargets(branch(MI, _) BRANCHES => BRANCHES, _), V) ... </k> requires notBool #switchMatch(MI, V) [preserves-definedness]
173+
rule <k> #selectBlock(switchTargets(branch(MI, _) BRANCHES => BRANCHES, _), V) ... </k>
174+
requires notBool #switchMatch(MI, V)
175+
andBool #switchCanUse(V)
176+
[preserves-definedness]
171177
172178
syntax Bool ::= #switchMatch ( MIRInt , Value ) [function]
173179
174180
rule #switchMatch(0, BoolVal(B) ) => notBool B
175181
rule #switchMatch(1, BoolVal(B) ) => B
176182
rule #switchMatch(I, Integer(I2, WIDTH, _)) => I ==Int truncate(I2, WIDTH, Unsigned) requires 0 <Int WIDTH
177183
rule #switchMatch(I, Integer(I2, 0 , _)) => I ==Int I2
184+
185+
syntax Bool ::= #switchCanUse ( Value ) [function, total]
186+
// ------------------------------------------------------
187+
rule #switchCanUse(Integer(_, _, _)) => true
188+
rule #switchCanUse( BoolVal( _ ) ) => true
189+
rule #switchCanUse( thunk( _ ) ) => true
190+
rule #switchCanUse( _OTHER ) => false [owise]
178191
```
179192

180193
`Return` simply returns from a function call, using the information

kmir/src/kmir/kdist/mir-semantics/rt/data.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -613,11 +613,19 @@ An attempt to read more elements than the length of the accessed array is undefi
613613
// helper rewrite to implement truncating slices to required size
614614
syntax KItem ::= #derefTruncate ( MetadataSize , ProjectionElems )
615615
// ----------------------------------------------------------------------------------------
616-
// no metadata, no change to the value
617-
rule <k> #traverseProjection( DEST, VAL, .ProjectionElems, CTXTS) ~> #derefTruncate(noMetadataSize, PROJS)
616+
// values other than `Range` do not have metadata anyway, they are passed along unchanged
617+
rule <k> #traverseProjection( DEST, VAL , .ProjectionElems, CTXTS) ~> #derefTruncate(noMetadataSize, PROJS)
618618
=> #traverseProjection(DEST, VAL, PROJS, CTXTS)
619619
...
620620
</k>
621+
requires notBool isRange(VAL)
622+
623+
// TODO move these to value.md
624+
syntax Bool ::= isRange ( Value ) [function, total]
625+
// ------------------------------------------------
626+
rule isRange(Range(_)) => true
627+
rule isRange( _OTHER ) => false [owise]
628+
621629
// staticSize metadata requires an array of suitable length and truncates it
622630
rule <k> #traverseProjection( DEST, Range(ELEMS), .ProjectionElems, CTXTS) ~> #derefTruncate(staticSize(SIZE), PROJS)
623631
=> #traverseProjection(DEST, Range(range(ELEMS, 0, size(ELEMS) -Int SIZE)), PROJS, CTXTS)
@@ -630,6 +638,12 @@ An attempt to read more elements than the length of the accessed array is undefi
630638
...
631639
</k>
632640
requires 0 <=Int SIZE andBool SIZE <=Int size(ELEMS) [preserves-definedness] // range parameters checked
641+
// If an array was projected to but no metadata is available, use the head element
642+
rule <k> #traverseProjection( DEST, Range(ListItem(VAL) _:List), .ProjectionElems, CTXTS) ~> #derefTruncate(noMetadataSize, PROJS)
643+
=> #traverseProjection(DEST, VAL, PROJS, CTXTS)
644+
...
645+
</k>
646+
[preserves-definedness]
633647
634648
// Ref, 0 < OFFSET, 0 < PTR_OFFSET, ToStack
635649
rule <k> #traverseProjection(
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn main() {
2+
let arr = [11, 22, 33];
3+
let mid_ref = unsafe { arr.get_unchecked(1) };
4+
let mid = *mid_ref;
5+
assert!(mid == 22);
6+
let last = unsafe { arr.get_unchecked(2) };
7+
assert!(*last == 33);
8+
}

0 commit comments

Comments
 (0)