Skip to content

Commit 7d26c82

Browse files
authored
Add runner script for fuzzing (#76)
1 parent 6d91599 commit 7d26c82

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#!/usr/bin/env -S uv --project ./mir-semantics/kmir run
2+
3+
import logging
4+
import re
5+
import sys
6+
from argparse import ArgumentParser
7+
from pathlib import Path
8+
from typing import TYPE_CHECKING
9+
10+
from kmir.kmir import KMIR
11+
from kmir.smir import SMIRInfo
12+
from pyk.kore.tools import kore_print
13+
from pyk.utils import unique
14+
15+
if TYPE_CHECKING:
16+
from argparse import Namespace
17+
from collections.abc import Iterable
18+
from typing import Final
19+
20+
21+
# Basic configuration
22+
TEST_PREFIX: Final = 'pinocchio_token_program::entrypoint::'
23+
TEST_PATTERN: Final = re.compile(r'\|\s*(test_[a-zA-Z0-9_]+)\s*\|')
24+
DEFAULT_SEEDS: Final = list(range(10))
25+
26+
27+
# Logger setup
28+
LOGGER: Final = logging.getLogger('ptoken.fuzzer')
29+
LOG_FORMAT: Final = '%(levelname)s %(asctime)s %(name)s - %(message)s'
30+
logging.basicConfig(level=logging.INFO, format=LOG_FORMAT)
31+
logging.getLogger('pyk').setLevel(logging.WARNING)
32+
33+
34+
# Paths
35+
CWD: Final = Path().resolve()
36+
ROOT_DIR: Final = (Path(__file__).parent).relative_to(CWD)
37+
TEST_FILE: Final = ROOT_DIR / 'proofs.md'
38+
ARTEFACTS_DIR = ROOT_DIR / 'artefacts'
39+
SMIR_FILE: Final = ARTEFACTS_DIR / 'p-token.smir.json'
40+
TARGET_DIR: Final = ARTEFACTS_DIR / 'fuzzing-kompiled'
41+
RESULT_DIR: Final = ARTEFACTS_DIR / 'fuzzing'
42+
43+
44+
sys.setrecursionlimit(10**8)
45+
46+
47+
def main(
48+
tests: Iterable[str] | None,
49+
seeds: Iterable[int] | None,
50+
) -> None:
51+
LOGGER.info('Setting up fuzzer')
52+
53+
tests = load_tests(tests)
54+
LOGGER.info(f'The following tests will be run: {", ".join(tests)}')
55+
56+
seeds = list(unique(seeds)) if seeds is not None else DEFAULT_SEEDS
57+
LOGGER.info(
58+
f'The following seeds will be used: {", ".join(str(seed) for seed in seeds)}'
59+
)
60+
61+
smir_info = load_smir()
62+
LOGGER.info(f'SMIR file parsed: {SMIR_FILE}')
63+
64+
kmir = load_kmir(smir_info)
65+
66+
RESULT_DIR.mkdir(exist_ok=True)
67+
68+
LOGGER.info('Starting fuzzer')
69+
for test in tests:
70+
for seed in seeds:
71+
fuzz(kmir=kmir, smir_info=smir_info, test=test, seed=seed)
72+
73+
LOGGER.info('Fuzzing complete')
74+
75+
76+
def load_tests(tests: Iterable[str] | None) -> list[str]:
77+
all_tests = TEST_PATTERN.findall(TEST_FILE.read_text())
78+
79+
if tests is None:
80+
return all_tests
81+
82+
res = list(unique(tests))
83+
not_found = [test for test in tests if test not in set(all_tests)]
84+
if not_found:
85+
raise ValueError(f'Tests not found: {", ".join(not_found)}')
86+
87+
return res
88+
89+
90+
def load_smir() -> SMIRInfo:
91+
if not SMIR_FILE.exists():
92+
raise ValueError(
93+
f'SMIR file {SMIR_FILE} does not exist. Run ./setup.sh to generate it'
94+
)
95+
return SMIRInfo.from_file(SMIR_FILE)
96+
97+
98+
def load_kmir(smir_info: SMIRInfo) -> KMIR:
99+
return KMIR.from_kompiled_kore(smir_info, target_dir=TARGET_DIR, symbolic=False)
100+
101+
102+
def fuzz(kmir: KMIR, smir_info: SMIRInfo, test: str, seed: int) -> None:
103+
LOGGER.info(f'Fuzzing: test={test}, seed={seed}')
104+
105+
pattern = kmir.run_smir(
106+
smir_info=smir_info,
107+
start_symbol=f'{TEST_PREFIX}{test}',
108+
depth=None,
109+
seed=seed,
110+
)
111+
112+
kore_text = pattern.text
113+
kore_file = RESULT_DIR / f'{test}-{seed}.kore'
114+
kore_file.write_text(kore_text)
115+
LOGGER.info(f'KORE file written: {kore_file}')
116+
117+
pretty_text = kore_print(
118+
pattern=kore_text,
119+
definition_dir=TARGET_DIR / 'llvm',
120+
)
121+
pretty_file = RESULT_DIR / f'{test}-{seed}.pretty'
122+
pretty_file.write_text(pretty_text)
123+
LOGGER.info(f'Pretty file written: {pretty_file}')
124+
125+
126+
def parse_args() -> Namespace:
127+
parser = ArgumentParser(description='PToken fuzzer')
128+
parser.add_argument('--tests', nargs='+', action='extend')
129+
parser.add_argument('--seeds', nargs='+', action='extend', type=int)
130+
return parser.parse_args()
131+
132+
133+
if __name__ == '__main__':
134+
ns = parse_args()
135+
main(tests=ns.tests, seeds=ns.seeds)

0 commit comments

Comments
 (0)