haskell_observe.py (2055B)
1 #!/usr/bin/env python3 2 """Bounded whole-tree observation of an explicit bundle export via Haskell ABI.""" 3 import argparse 4 from pathlib import Path 5 import resource 6 import sys 7 from executable_object import FLAT, verify_payload 8 9 sys.path.insert(0, str(Path(__file__).resolve().parent.parent / 'ext/haskell/python')) 10 from tricu import Library 11 12 13 def main(): 14 parser = argparse.ArgumentParser(description=__doc__) 15 for key in ('library', 'bundle', 'argument', 'output'): 16 parser.add_argument('--' + key, type=Path, required=True) 17 parser.add_argument('--export', required=True) 18 args = parser.parse_args() 19 # RTS virtual reservation is distinct from the supervisor's 512-MiB RSS cap. 20 for kind, limit in [(resource.RLIMIT_AS, 1024 * 1024**2), 21 (resource.RLIMIT_STACK, 8 * 1024**2), 22 (resource.RLIMIT_CPU, 60), (resource.RLIMIT_CORE, 0)]: 23 resource.setrlimit(kind, (limit, limit)) 24 data = args.argument.read_bytes() 25 verify_payload(FLAT, data) 26 with Library(args.library).context() as ctx, ctx.scope() as roots: 27 stack = [] 28 for tag in reversed(data): 29 children = [stack.pop() for _ in range(tag)] 30 value = (roots.leaf, roots.stem, roots.fork)[tag](*children) 31 for child in children: 32 roots.release(child) 33 stack.append(value) 34 assert len(stack) == 1 35 worker = roots.load_bundle(args.bundle.read_bytes(), args.export) 36 current = roots.apply(worker, stack[0]) 37 todo, output = [current], bytearray() 38 while todo: 39 value = todo.pop() 40 tag = ctx.kind(value) 41 output.append(tag) 42 children = [roots.child(value, i) for i in range(tag)] 43 todo.extend(reversed(children)) 44 roots.release(value) 45 if len(output) > 1024 * 1024: 46 raise ValueError('test output boundary') 47 verify_payload(FLAT, output) 48 args.output.write_bytes(output) 49 50 51 if __name__ == '__main__': 52 main()