Skip to content

Commit fa28e3f

Browse files
authored
Update feature/proofs with master (#791)
- #787 - #783 - #780 - #790
2 parents 2cdcd8e + c42d05d commit fa28e3f

32 files changed

+392
-79
lines changed

deps/k_release

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
7.1.300
1+
7.1.301

flake.lock

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
inputs.flake-utils.follows = "flake-utils";
1313
};
1414

15-
k-framework.url = "github:runtimeverification/k/v7.1.300";
15+
k-framework.url = "github:runtimeverification/k/v7.1.301";
1616
k-framework = {
1717
inputs.flake-utils.follows = "flake-utils";
1818
inputs.nixpkgs.follows = "nixpkgs";

kmir/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ version = "0.3.181"
88
description = ""
99
requires-python = ">=3.10"
1010
dependencies = [
11-
"kframework==v7.1.300",
11+
"kframework==v7.1.301",
1212
"rust-demangler==1.0",
1313
]
1414

kmir/src/kmir/__main__.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
ProveRSOpts,
2525
PruneOpts,
2626
RunOpts,
27+
SectionEdgeOpts,
2728
ShowOpts,
2829
ViewOpts,
2930
)
@@ -141,6 +142,38 @@ def _kmir_prune(opts: PruneOpts) -> None:
141142
proof.write_proof_data()
142143

143144

145+
def _kmir_section_edge(opts: SectionEdgeOpts) -> None:
146+
# Proof dir is checked to be some in arg parsing for instructive errors
147+
assert opts.proof_dir is not None
148+
149+
if not APRProof.proof_data_exists(opts.id, opts.proof_dir):
150+
raise ValueError(f'Proof id {opts.id} not found in proof dir {opts.proof_dir}')
151+
152+
target_path = opts.proof_dir / opts.id
153+
154+
_LOGGER.info(f'Reading proof from disc: {opts.proof_dir}, {opts.id}')
155+
apr_proof = APRProof.read_proof_data(opts.proof_dir, opts.id)
156+
157+
smir_info = SMIRInfo.from_file(target_path / 'smir.json')
158+
159+
kmir = KMIR.from_kompiled_kore(smir_info, symbolic=True, bug_report=opts.bug_report, target_dir=target_path)
160+
161+
source_id, target_id = opts.edge
162+
_LOGGER.info(f'Attempting to add {opts.sections} sections from node {source_id} to node {target_id}')
163+
164+
with kmir.kcfg_explore(apr_proof.id) as kcfg_explore:
165+
node_ids = kcfg_explore.section_edge(
166+
apr_proof.kcfg,
167+
source_id=int(source_id),
168+
target_id=int(target_id),
169+
logs=apr_proof.logs,
170+
sections=opts.sections,
171+
)
172+
_LOGGER.info(f'Added nodes on edge {(source_id, target_id)}: {node_ids}')
173+
174+
apr_proof.write_proof_data()
175+
176+
144177
def _kmir_info(opts: InfoOpts) -> None:
145178
smir_info = SMIRInfo.from_file(opts.smir_file)
146179

@@ -171,6 +204,8 @@ def kmir(args: Sequence[str]) -> None:
171204
_kmir_show(opts)
172205
case PruneOpts():
173206
_kmir_prune(opts)
207+
case SectionEdgeOpts():
208+
_kmir_section_edge(opts)
174209
case ProveRSOpts():
175210
_kmir_prove_rs(opts)
176211
case LinkOpts():
@@ -210,6 +245,84 @@ def _arg_parser() -> ArgumentParser:
210245
'--max-iterations', metavar='ITERATIONS', type=int, help='max number of proof iterations to take'
211246
)
212247
prove_args.add_argument('--reload', action='store_true', help='Force restarting proof')
248+
prove_args.add_argument(
249+
'--break-on-calls', dest='break_on_calls', action='store_true', help='Break on all function and intrinsic calls'
250+
)
251+
prove_args.add_argument(
252+
'--break-on-function-calls',
253+
dest='break_on_function_calls',
254+
action='store_true',
255+
help='Break on function calls (not intrinsics)',
256+
)
257+
prove_args.add_argument(
258+
'--break-on-intrinsic-calls',
259+
dest='break_on_intrinsic_calls',
260+
action='store_true',
261+
help='Break on intrinsic calls (not other functions)',
262+
)
263+
prove_args.add_argument(
264+
'--break-on-thunk', dest='break_on_thunk', action='store_true', help='Break on thunk evaluation'
265+
)
266+
prove_args.add_argument(
267+
'--break-every-statement',
268+
dest='break_every_statement',
269+
action='store_true',
270+
help='Break on every MIR Statement execution',
271+
)
272+
prove_args.add_argument(
273+
'--break-on-terminator-goto',
274+
dest='break_on_terminator_goto',
275+
action='store_true',
276+
help='Break on Goto terminator',
277+
)
278+
prove_args.add_argument(
279+
'--break-on-terminator-switch-int',
280+
dest='break_on_terminator_switch_int',
281+
action='store_true',
282+
help='Break on SwitchInt terminator',
283+
)
284+
prove_args.add_argument(
285+
'--break-on-terminator-return',
286+
dest='break_on_terminator_return',
287+
action='store_true',
288+
help='Break on Return terminator',
289+
)
290+
prove_args.add_argument(
291+
'--break-on-terminator-call',
292+
dest='break_on_terminator_call',
293+
action='store_true',
294+
help='Break on Call terminator',
295+
)
296+
prove_args.add_argument(
297+
'--break-on-terminator-assert',
298+
dest='break_on_terminator_assert',
299+
action='store_true',
300+
help='Break on Assert terminator',
301+
)
302+
prove_args.add_argument(
303+
'--break-on-terminator-drop',
304+
dest='break_on_terminator_drop',
305+
action='store_true',
306+
help='Break on Drop terminator',
307+
)
308+
prove_args.add_argument(
309+
'--break-on-terminator-unreachable',
310+
dest='break_on_terminator_unreachable',
311+
action='store_true',
312+
help='Break on Unreachable terminator',
313+
)
314+
prove_args.add_argument(
315+
'--break-every-terminator',
316+
dest='break_every_terminator',
317+
action='store_true',
318+
help='Break on every MIR terminator execution',
319+
)
320+
prove_args.add_argument(
321+
'--break-every-step',
322+
dest='break_every_step',
323+
action='store_true',
324+
help='Break on every MIR step (statements and terminators)',
325+
)
213326

214327
proof_args = ArgumentParser(add_help=False)
215328
proof_args.add_argument('id', metavar='PROOF_ID', help='The id of the proof to view')
@@ -287,6 +400,16 @@ def _arg_parser() -> ArgumentParser:
287400
)
288401
prune_parser.add_argument('node_id', metavar='NODE', type=int, help='The node to prune')
289402

403+
section_edge_parser = command_parser.add_parser(
404+
'section-edge', help='Break an edge into sections', parents=[kcli_args.logging_args, proof_args]
405+
)
406+
section_edge_parser.add_argument(
407+
'edge', type=lambda s: tuple(s.split(',')), help='Edge to section in CFG (format: `source,target`)'
408+
)
409+
section_edge_parser.add_argument(
410+
'--sections', type=int, default=2, help='Number of sections to make from edge (>= 2, default: 2)'
411+
)
412+
290413
prove_rs_parser = command_parser.add_parser(
291414
'prove-rs', help='Prove a rust program', parents=[kcli_args.logging_args, prove_args]
292415
)
@@ -354,6 +477,11 @@ def _parse_args(ns: Namespace) -> KMirOpts:
354477
case 'prune':
355478
proof_dir = Path(ns.proof_dir)
356479
return PruneOpts(proof_dir, ns.id, ns.node_id)
480+
case 'section-edge':
481+
if ns.proof_dir is None:
482+
raise ValueError('Must pass --proof-dir to section-edge command')
483+
proof_dir = Path(ns.proof_dir)
484+
return SectionEdgeOpts(proof_dir, ns.id, ns.edge, ns.sections)
357485
case 'prove-rs':
358486
return ProveRSOpts(
359487
rs_file=Path(ns.rs_file),
@@ -365,6 +493,20 @@ def _parse_args(ns: Namespace) -> KMirOpts:
365493
save_smir=ns.save_smir,
366494
smir=ns.smir,
367495
start_symbol=ns.start_symbol,
496+
break_on_calls=ns.break_on_calls,
497+
break_on_function_calls=ns.break_on_function_calls,
498+
break_on_intrinsic_calls=ns.break_on_intrinsic_calls,
499+
break_on_thunk=ns.break_on_thunk,
500+
break_every_statement=ns.break_every_statement,
501+
break_on_terminator_goto=ns.break_on_terminator_goto,
502+
break_on_terminator_switch_int=ns.break_on_terminator_switch_int,
503+
break_on_terminator_return=ns.break_on_terminator_return,
504+
break_on_terminator_call=ns.break_on_terminator_call,
505+
break_on_terminator_assert=ns.break_on_terminator_assert,
506+
break_on_terminator_drop=ns.break_on_terminator_drop,
507+
break_on_terminator_unreachable=ns.break_on_terminator_unreachable,
508+
break_every_terminator=ns.break_every_terminator,
509+
break_every_step=ns.break_every_step,
368510
)
369511
case 'link':
370512
return LinkOpts(

kmir/src/kmir/kast.py

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
import logging
44
from itertools import count
5+
from random import Random
56
from typing import TYPE_CHECKING, NamedTuple
67

7-
from pyk.kast.inner import KApply, KSort, KVariable, Subst, build_cons
8+
from pyk.kast.inner import KApply, KSequence, KSort, KVariable, Subst, build_cons
89
from pyk.kast.manip import free_vars, split_config_from
910
from pyk.kast.prelude.collections import list_empty, list_of
10-
from pyk.kast.prelude.kint import eqInt, leInt
11+
from pyk.kast.prelude.kint import eqInt, intToken, leInt
1112
from pyk.kast.prelude.ml import mlEqualsTrue
1213
from pyk.kast.prelude.utils import token
1314

@@ -29,7 +30,6 @@
2930

3031
if TYPE_CHECKING:
3132
from collections.abc import Iterable, Iterator, Mapping, Sequence
32-
from random import Random
3333
from typing import Any, Final
3434

3535
from pyk.kast import KInner
@@ -56,7 +56,7 @@ class SymbolicMode(NamedTuple): ...
5656

5757

5858
class RandomMode(NamedTuple):
59-
random: Random
59+
seed: int
6060

6161

6262
CallConfigMode = ConcreteMode | SymbolicMode | RandomMode
@@ -89,12 +89,12 @@ def make_call_config(
8989
types=smir_info.types,
9090
)
9191
return CallConfig(config=config, constraints=tuple(constraints))
92-
case RandomMode(random):
92+
case RandomMode(seed):
9393
config = _make_random_call_config(
9494
definition=definition,
9595
fn_data=fn_data,
9696
types=smir_info.types,
97-
random=random,
97+
seed=seed,
9898
)
9999
return CallConfig(config=config, constraints=())
100100

@@ -148,6 +148,7 @@ def _make_concrete_call_config(
148148
definition=definition,
149149
fn_data=fn_data,
150150
localvars=[],
151+
seed=None,
151152
)
152153

153154

@@ -156,13 +157,14 @@ def _make_random_call_config(
156157
definition: KDefinition,
157158
fn_data: _FunctionData,
158159
types: Mapping[Ty, TypeMetadata],
159-
random: Random,
160+
seed: int,
160161
) -> KInner:
161-
localvars = _random_locals(random, fn_data.args, types)
162+
localvars = _random_locals(Random(seed), fn_data.args, types)
162163
return _make_concrete_call_config_with_locals(
163164
definition=definition,
164165
fn_data=fn_data,
165166
localvars=localvars,
167+
seed=seed,
166168
)
167169

168170

@@ -171,23 +173,35 @@ def _make_concrete_call_config_with_locals(
171173
definition: KDefinition,
172174
fn_data: _FunctionData,
173175
localvars: list[KInner],
176+
seed: int | None,
174177
) -> KInner:
175178
def init_subst() -> dict[str, KInner]:
176179
init_config = definition.init_config(KSort('GeneratedTopCell'))
177180
_, res = split_config_from(init_config)
178181
return res
179182

180-
# The configuration is the default initial configuration, with the K cell updated with the call terminator
183+
# The configuration is the default initial configuration,
184+
# with the K cell updated with the call terminator (and with an srandInt call, if seed is set)
181185
# TODO: see if this can be expressed in more simple terms
186+
187+
k_cell = fn_data.call_terminator
188+
if seed is not None:
189+
# Seed the pseudorandom generator. This is necessary for cheatcode use in concrete execution.
190+
k_cell = KSequence(
191+
KApply('srandInt(_)_INT-COMMON_K_Int', intToken(seed)),
192+
k_cell,
193+
)
194+
182195
subst = Subst(
183196
{
184197
**init_subst(),
185198
**{
186-
'K_CELL': fn_data.call_terminator,
199+
'K_CELL': k_cell,
187200
'LOCALS_CELL': list_of(localvars),
188201
},
189202
}
190203
)
204+
191205
empty_config = definition.empty_config(KSort('GeneratedTopCell'))
192206
config = subst(empty_config)
193207
assert not free_vars(config), f'Config by construction should not have any free variables: {config}'

0 commit comments

Comments
 (0)