tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

check-compiler.py (2977B)


      1 """Correctness/security controls for the opt-in prepared-input benchmark."""
      2 import json
      3 import pathlib
      4 import shutil
      5 import struct
      6 import subprocess
      7 import sys
      8 import tempfile
      9 
     10 root = pathlib.Path(sys.argv[1])
     11 data = root / 'compiler-data'
     12 manifest = json.loads((data/'manifest.json').read_text())
     13 
     14 def commands(directory, case):
     15     return [
     16         [str(root/'bin/compiler-native'),str(directory),str(directory/str(case))],
     17         [str(root/'bin/wasmtime'),'run','--dir',f'{directory}::/data',str(root/'bin/compiler.wasm'),'/data','/data/'+str(case)],
     18         [str(root/'bin/node'),str(root/'bin/node-wasi.mjs'),str(root/'bin/compiler.wasm'),str(directory),str(case)],
     19     ]
     20 
     21 def check(command, error=None, rts=True):
     22     result = subprocess.run(command + (['+RTS','-T','-M512m','-K8m','-RTS'] if rts else []),
     23                             capture_output=True,text=True,timeout=120)
     24     if error is None:
     25         assert result.returncode == 0, result.stderr
     26         if rts:
     27             metrics=json.loads(result.stdout)
     28             assert metrics['allocated_bytes']>0
     29     else:
     30         assert result.returncode != 0, 'negative control unexpectedly succeeded'
     31         assert error in result.stderr, result.stderr
     32 
     33 for case in manifest['cases']:
     34     for command in commands(data,case['id']):
     35         check(command)
     36 # TS oracle smoke is not a timing gate.
     37 check([str(root/'bin/node'),str(root/'bin/ts-compiler.mjs'),str(root/'site'),'0'],rts=False)
     38 with tempfile.TemporaryDirectory() as tmp:
     39     tmp=pathlib.Path(tmp)
     40     bad=tmp/'bad'; shutil.copytree(data,bad)
     41     (bad/'0/expected').write_text('ok\nid\t0\n')
     42     for command in commands(bad,0): check(command,'compiler golden mismatch')
     43     shutil.copyfile(data/'0/expected',bad/'0/expected')
     44     b=bytearray((bad/'compiler.dag').read_bytes())
     45     b[8]=1; struct.pack_into('<I',b,9,0)  # node zero referring to itself
     46     (bad/'compiler.dag').write_bytes(b)
     47     for command in commands(bad,0): check(command,'invalid DAG record')
     48     (bad/'compiler.dag').write_bytes(b'bad')
     49     for command in commands(bad,0): check(command,'truncated DAG')
     50     site=tmp/'site'; site.mkdir()
     51     original=root/'site'
     52     for name in ['dist','bundles','test']:
     53         (site/name).symlink_to((original/name).resolve(),target_is_directory=True)
     54     descriptor=json.loads((original/'compiler.json').read_text())
     55     # Corrupt bytes under the correct pinned filename: authentication must fail.
     56     (site/'bundles').unlink(); (site/'bundles').mkdir()
     57     (site/'bundles'/(descriptor['hash']+'.arboricx')).write_bytes(b'corrupt')
     58     (site/'compiler.json').write_text(json.dumps(descriptor))
     59     check([str(root/'bin/node'),str(root/'bin/prepare-compiler.mjs'),str(site),str(tmp/'prepared')],
     60           'AssertionError',rts=False)
     61 # No preopen: cannot reach the compiler inputs.
     62 check([str(root/'bin/wasmtime'),'run',str(root/'bin/compiler.wasm'),'/data','/data/0'],
     63       'does not exist')
     64 print('compiler goldens and negative controls passed')