Skip to content

Commit 024f2d3

Browse files
authored
Update feature/p-token with origin/master (#734)
2 parents b788e5b + 6766c70 commit 024f2d3

33 files changed

+275
-316
lines changed

kmir/src/kmir/__main__.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
from .build import HASKELL_DEF_DIR, LLVM_DEF_DIR, LLVM_LIB_DIR
1818
from .cargo import CargoProject
19-
from .kmir import KMIR, DecodeMode, KMIRAPRNodePrinter
19+
from .kmir import KMIR, KMIRAPRNodePrinter
2020
from .linker import link
2121
from .options import (
2222
GenSpecOpts,
@@ -370,13 +370,6 @@ def _arg_parser() -> ArgumentParser:
370370
prove_rs_parser.add_argument(
371371
'--start-symbol', type=str, metavar='SYMBOL', default='main', help='Symbol name to begin execution from'
372372
)
373-
prove_rs_parser.add_argument(
374-
'--decode-mode',
375-
type=DecodeMode,
376-
metavar='DECODE_MODE',
377-
default=DecodeMode.NONE,
378-
help='Allocation decoding mode: NONE (default), PARTIAL, or FULL',
379-
)
380373

381374
link_parser = command_parser.add_parser(
382375
'link', help='Link together 2 or more SMIR JSON files', parents=[kcli_args.logging_args]
@@ -455,7 +448,6 @@ def _parse_args(ns: Namespace) -> KMirOpts:
455448
save_smir=ns.save_smir,
456449
smir=ns.smir,
457450
start_symbol=ns.start_symbol,
458-
decode_mode=ns.decode_mode,
459451
)
460452
case 'link':
461453
return LinkOpts(

kmir/src/kmir/alloc.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,21 +71,21 @@ def from_dict(dct: dict[str, Any]) -> Allocation:
7171

7272
@dataclass
7373
class ProvenanceMap:
74-
ptrs: list[ProvenanceItem]
74+
ptrs: list[ProvenanceEntry]
7575

7676
@staticmethod
7777
def from_dict(dct: dict[str, Any]) -> ProvenanceMap:
7878
return ProvenanceMap(
7979
ptrs=[
80-
ProvenanceItem(
81-
size=int(size),
82-
prov=AllocId(prov),
80+
ProvenanceEntry(
81+
offset=int(size),
82+
alloc_id=AllocId(prov),
8383
)
8484
for size, prov in dct['ptrs']
8585
],
8686
)
8787

8888

89-
class ProvenanceItem(NamedTuple):
90-
size: int
91-
prov: AllocId
89+
class ProvenanceEntry(NamedTuple):
90+
offset: int
91+
alloc_id: AllocId

kmir/src/kmir/decoding.py

Lines changed: 86 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,46 @@
11
from __future__ import annotations
22

33
from dataclasses import dataclass
4-
from typing import TYPE_CHECKING, NamedTuple
4+
from typing import TYPE_CHECKING
55

66
from pyk.kast.inner import KApply
7-
from pyk.kast.prelude.bytes import bytesToken
8-
from pyk.kast.prelude.kint import intToken
9-
10-
from .alloc import Allocation, AllocInfo, Memory, ProvenanceMap
11-
from .ty import ArrayT, Bool, EnumT, Int, IntTy, Uint
12-
from .value import AggregateValue, BoolValue, IntValue, RangeValue, Value
7+
from pyk.kast.prelude.string import stringToken
8+
9+
from .alloc import Allocation, AllocInfo, Memory, ProvenanceEntry, ProvenanceMap
10+
from .ty import ArrayT, Bool, EnumT, Int, IntTy, PtrT, RefT, Str, Uint
11+
from .value import (
12+
NO_METADATA,
13+
AggregateValue,
14+
AllocRefValue,
15+
BoolValue,
16+
DynamicSize,
17+
IntValue,
18+
RangeValue,
19+
StaticSize,
20+
StrValue,
21+
Value,
22+
)
1323

1424
if TYPE_CHECKING:
1525
from collections.abc import Mapping
1626

1727
from pyk.kast import KInner
1828

19-
from .alloc import AllocId
2029
from .ty import Ty, TypeMetadata, UintTy
30+
from .value import Metadata
2131

2232

2333
@dataclass
2434
class UnableToDecodeValue(Value):
25-
data: bytes
26-
type_info: TypeMetadata
35+
msg: str
2736

2837
def to_kast(self) -> KInner:
2938
return KApply(
30-
'Evaluation::UnableToDecodeValue',
31-
bytesToken(self.data),
32-
KApply('TypeInfo::VoidType'), # TODO: TypeInfo -> KAST transformation
39+
'Evaluation::UnableToDecodePy',
40+
stringToken(self.msg),
3341
)
3442

3543

36-
@dataclass
37-
class UnableToDecodeAlloc(Value):
38-
data: bytes
39-
ty: Ty
40-
41-
def to_kast(self) -> KInner:
42-
return KApply(
43-
'Evaluation::UnableToDecodeAlloc',
44-
bytesToken(self.data),
45-
KApply('ty', intToken(self.ty)),
46-
KApply('ProvenanceMapEntries::empty'), # TODO
47-
)
48-
49-
50-
class ProvenanceMapEntry(NamedTuple):
51-
offset: int
52-
alloc_id: AllocId
53-
54-
5544
def decode_alloc_or_unable(alloc_info: AllocInfo, types: Mapping[Ty, TypeMetadata]) -> Value:
5645
match alloc_info:
5746
case AllocInfo(
@@ -66,27 +55,81 @@ def decode_alloc_or_unable(alloc_info: AllocInfo, types: Mapping[Ty, TypeMetadat
6655
),
6756
):
6857
data = bytes(n or 0 for n in bytez)
58+
return _decode_memory_alloc_or_unable(data=data, ptrs=ptrs, ty=ty, types=types)
59+
case _:
60+
raise AssertionError('Unhandled case')
61+
6962

70-
if not ptrs: # TODO generalize to lists with at most one entry
71-
type_info = types[ty]
72-
return decode_value_or_unable(data=data, type_info=type_info, types=types)
63+
def _decode_memory_alloc_or_unable(
64+
data: bytes,
65+
ptrs: list[ProvenanceEntry],
66+
ty: Ty,
67+
types: Mapping[Ty, TypeMetadata],
68+
) -> Value:
69+
try:
70+
type_info = types[ty]
71+
except KeyError:
72+
return UnableToDecodeValue(f'Unknown type: {ty}')
7373

74-
return UnableToDecodeAlloc(data=data, ty=ty)
74+
match ptrs:
75+
case []:
76+
return decode_value_or_unable(data=data, type_info=type_info, types=types)
77+
78+
case [ProvenanceEntry(0, alloc_id)]:
79+
if (pointee_ty := _pointee_ty(type_info)) is not None: # ensures this is a reference type
80+
try:
81+
pointee_type_info = types[pointee_ty]
82+
except KeyError:
83+
return UnableToDecodeValue(f'Unknown pointee type: {pointee_ty}')
84+
85+
metadata = _metadata(pointee_type_info)
86+
87+
if len(data) == 8:
88+
# single slim pointer (assumes usize == u64)
89+
return AllocRefValue(alloc_id=alloc_id, metadata=metadata)
90+
91+
if len(data) == 16 and metadata == DynamicSize(1):
92+
# sufficient data to decode dynamic size (assumes usize == u64)
93+
# expect fat pointer
94+
return AllocRefValue(
95+
alloc_id=alloc_id,
96+
metadata=DynamicSize(int.from_bytes(data[8:16], byteorder='little', signed=False)),
97+
)
98+
99+
return UnableToDecodeValue(f'Unable to decode alloc: {data!r}, of type: {type_info}')
100+
101+
102+
def _pointee_ty(type_info: TypeMetadata) -> Ty | None:
103+
match type_info:
104+
case PtrT(ty) | RefT(ty):
105+
return ty
75106
case _:
76-
raise AssertionError('Unhandled case')
107+
return None
108+
109+
110+
def _metadata(type_info: TypeMetadata) -> Metadata:
111+
match type_info:
112+
case ArrayT(length=None):
113+
return DynamicSize(1) # 1 is a placeholder, the actual size is inferred from the slice data
114+
case ArrayT(length=int() as length):
115+
return StaticSize(length)
116+
case _:
117+
return NO_METADATA
77118

78119

79120
def decode_value_or_unable(data: bytes, type_info: TypeMetadata, types: Mapping[Ty, TypeMetadata]) -> Value:
80121
try:
81122
return decode_value(data=data, type_info=type_info, types=types)
82-
except ValueError:
83-
return UnableToDecodeValue(data=data, type_info=type_info)
123+
except ValueError as err:
124+
return UnableToDecodeValue(f'Unable to decode value: {data!r}, of type: {type_info}: {err}')
84125

85126

86127
def decode_value(data: bytes, type_info: TypeMetadata, types: Mapping[Ty, TypeMetadata]) -> Value:
87128
match type_info:
88129
case Bool():
89130
return _decode_bool(data)
131+
case Str():
132+
return _decode_str(data)
90133
case Uint(int_ty) | Int(int_ty):
91134
return _decode_int(data, int_ty)
92135
case ArrayT(elem_ty, length):
@@ -107,6 +150,10 @@ def _decode_bool(data: bytes) -> Value:
107150
raise ValueError(f'Cannot decode as Bool: {data!r}')
108151

109152

153+
def _decode_str(data: bytes) -> Value:
154+
return StrValue(data.decode('utf-8'))
155+
156+
110157
def _decode_int(data: bytes, int_ty: IntTy | UintTy) -> Value:
111158
nbytes = int_ty.value
112159
if len(data) != nbytes:

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ will be `129`.
326326
327327
rule #switchMatch(0, BoolVal(B) ) => notBool B
328328
rule #switchMatch(1, BoolVal(B) ) => B
329-
rule #switchMatch(I, Integer(I2, WIDTH, _)) => I ==Int bitRangeInt(I2, 0, WIDTH)
329+
rule #switchMatch(I, Integer(I2, WIDTH, _)) => I ==Int truncate(I2, WIDTH, Unsigned)
330330
```
331331

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

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

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,16 @@ Therefore, its value range should be simplified for symbolic input asserted to b
8181

8282
```k
8383
rule truncate(VAL, WIDTH, Unsigned) => VAL
84-
requires VAL <Int (1 <<Int WIDTH)
84+
requires 0 <Int WIDTH
85+
andBool VAL <Int (1 <<Int WIDTH)
8586
andBool 0 <=Int VAL
86-
[simplification]
87+
[simplification, preserves-definedness] // , smt-lemma], but `Unsigned` needs to be smtlib
8788
8889
rule truncate(VAL, WIDTH, Signed) => VAL
89-
requires VAL <Int (1 <<Int (WIDTH -Int 1))
90+
requires 0 <Int WIDTH
91+
andBool VAL <Int (1 <<Int (WIDTH -Int 1))
9092
andBool 0 -Int (1 <<Int (WIDTH -Int 1)) <=Int VAL
91-
[simplification]
93+
[simplification, preserves-definedness] // , smt-lemma], but `Signed` needs to be smtlib
9294
```
9395

9496
However, `truncate` gets evaluated and is therefore not present any more for this simplification.
@@ -97,17 +99,6 @@ The following simplification rules operate on the expression created by evaluati
9799
power of two but the semantics will always operate with these particular ones.
98100

99101
```k
100-
rule VAL &Int MASK => VAL
101-
requires 0 <=Int VAL
102-
andBool VAL <=Int MASK
103-
andBool ( MASK ==Int bitmask8
104-
orBool MASK ==Int bitmask16
105-
orBool MASK ==Int bitmask32
106-
orBool MASK ==Int bitmask64
107-
orBool MASK ==Int bitmask128
108-
)
109-
[simplification, preserves-definedness]
110-
111102
syntax Int ::= "bitmask8" [macro]
112103
| "bitmask16" [macro]
113104
| "bitmask32" [macro]
@@ -120,6 +111,11 @@ power of two but the semantics will always operate with these particular ones.
120111
rule bitmask64 => ( 1 <<Int 64 ) -Int 1
121112
rule bitmask128 => ( 1 <<Int 128) -Int 1
122113
114+
rule VAL &Int bitmask8 => VAL requires 0 <=Int VAL andBool VAL <=Int bitmask8 [simplification, preserves-definedness, smt-lemma]
115+
rule VAL &Int bitmask16 => VAL requires 0 <=Int VAL andBool VAL <=Int bitmask16 [simplification, preserves-definedness, smt-lemma]
116+
rule VAL &Int bitmask32 => VAL requires 0 <=Int VAL andBool VAL <=Int bitmask32 [simplification, preserves-definedness, smt-lemma]
117+
rule VAL &Int bitmask64 => VAL requires 0 <=Int VAL andBool VAL <=Int bitmask64 [simplification, preserves-definedness, smt-lemma]
118+
rule VAL &Int bitmask128 => VAL requires 0 <=Int VAL andBool VAL <=Int bitmask128 [simplification, preserves-definedness, smt-lemma]
123119
```
124120

125121

0 commit comments

Comments
 (0)