def run_test_file(template_wasm_config, test_file_path, output_dir, cmd_args): global args test_name = os.path.basename(test_file_path) k_steps = get_steps_as_kseq(test_file_path, output_dir) final_config = None if cmd_args.log_level == 'none' or cmd_args.log_level == 'per-file': # Flatten the list of k_steps, just run them all in one go. k_steps = [('full', [y for (_, x) in k_steps for y in x])] (symbolic_config, init_subst) = pyk.splitConfigFrom(template_wasm_config) for i in range(len(k_steps)): step_name, curr_step = k_steps[i] if args.verbose: print('Executing step %s' % step_name) init_subst['K_CELL'] = KSequence(curr_step) init_config = pyk.substitute(symbolic_config, init_subst) input_json = config_to_kast_term(init_config) krun_args = ['--term', '--debug'] # Run: generate a new JSON as a temporary file, then read that as the new wasm state. if cmd_args.log_level != 'none': log_intermediate_state("%s_%d_%s.pre" % (test_name, i, step_name), init_config, output_dir) (rc, new_wasm_config, err) = pyk.krunJSONLegacy(WASM_definition_llvm_no_coverage_dir, input_json, krunArgs=krun_args, teeOutput=True) if rc != 0: print('output:\n%s' % new_wasm_config, file=sys.stderr) print( pyk.prettyPrintKast(new_wasm_config, WASM_symbols_llvm_no_coverage)) raise Exception("Received error while running: " + err) final_config = new_wasm_config if cmd_args.log_level != 'none': log_intermediate_state("%s_%d_%s" % (test_name, i, step_name), new_wasm_config, output_dir) # Check if the k cell is empty (symbolic_config, init_subst) = pyk.splitConfigFrom(new_wasm_config) k_cell = init_subst['K_CELL'] assert k_cell['node'] == 'KSequence' and k_cell[ 'arity'] == 0, "k cell not empty, contains a sequence of %d items.\nSee %s" % ( k_cell['arity'], output_dir) return final_config
def extractTrace(config): (_, subst) = pyk.splitConfigFrom(config) pEvents = subst['PROCESSED_EVENTS_CELL'] log_events = flattenList(pEvents) return [ makeSolidityCall(e, succeeds) for event in log_events for (e, succeeds) in extractCallEvents(event) ]
def detect_violations(config): (_, configSubst) = pyk.splitConfigFrom(config) properties = configSubst['PROPERTIES_CELL'] violations = [] for (prop, value) in flattenMap(properties): if pyk.isKApply(value) and value['label'] == 'Violated(_)_KMCD-PROPS_ViolationFSM_ViolationFSM': violations.append(prop['token']) return violations
def extractAsserts(config): (_, subst) = pyk.splitConfigFrom(config) snapshots = subst['KMCD_SNAPSHOTS_CELL'] [preState, postState] = flattenList(snapshots) stateDelta = pyk.pushDownRewrites(pyk.KRewrite(preState, postState)) (_, subst) = pyk.splitConfigFrom(stateDelta) asserts = [] for cell in subst.keys(): if pyk.isKRewrite(subst[cell]): contract = cell.split('_')[0] contract = contract[0] + contract[1:].lower() field = cell.split('_')[1].lower() if contract == 'Vat' and field == 'line': field = 'Line' rhs = subst[cell]['rhs'] asserts.extend(buildAsserts(contract, field, rhs)) stateDelta = noRewriteToDots(stateDelta) stateDelta = pyk.collapseDots(stateDelta) return (printMCD(stateDelta), asserts)
def extractTrace(config): (_, subst) = pyk.splitConfigFrom(config) pEvents = subst['PROCESSED_EVENTS_CELL'] log_events = flattenList(pEvents) call_events = [] last_event = None for event in log_events: if pyk.isKApply(event) and event[ 'label'] == 'Measure(_,_,_,_,_,_,_,_,_,_,_)_KMCD-PROPS_Measure_Rat_Map_Rat_Rat_Rat_Rat_Rat_Rat_Map_Rat_Map': if last_event is not None: call_events.extend(extractCallEvent(last_event)) last_event = event return call_events
def detect_violations(config): (_, configSubst) = pyk.splitConfigFrom(config) properties = configSubst['PROPERTIES_CELL'] violations = [] def _gatherViolations(fsmMap): if pyk.isKApply(fsmMap) and fsmMap['label'] == '_|->_': if fsmMap['args'][1] == pyk.KConstant( 'Violated_KMCD-PROPS_ViolationFSM'): violations.append(fsmMap['args'][0]['token']) return fsmMap pyk.traverseTopDown(properties, _gatherViolations) return violations
def get_coverage_data(term, cell_name, filter_func, collect_data_func): # TODO: Use traverseBottomUp. def filter_term(filter_func, term): res = [] if filter_func(term): res.append(term) if 'args' in term: for arg in term['args']: res.extend(filter_term(filter_func, arg)) return res cells = pyk.splitConfigFrom(term)[1] cov_cell = cells[cell_name] cov_data = filter_term(filter_func, cov_cell) result = [collect_data_func(entry) for entry in cov_data] return result
def get_init_config(init_term): kast_json = {'format': 'KAST', 'version': 1, 'term': init_term} (_, init_config, _) = krun(kast_json, *randomSeedArgs()) return pyk.splitConfigFrom(init_config)
def noRewriteToDots(config): (cfg, subst) = pyk.splitConfigFrom(config) for cell in subst.keys(): if not pyk.isKRewrite(subst[cell]): subst[cell] = pyk.ktokenDots return pyk.substitute(cfg, subst)
def get_init_config(init_term, debug = False): init_config = kmcdJSON(init_term, backend = 'llvm', debug = debug, kastArgs = [ '--sort', 'EthereumSimulation' ]) return pyk.splitConfigFrom(init_config)
def get_init_config(): init_term = { 'format': 'KAST', 'version': 1, 'term': KConstant('.List{"___WASM_Stmts_Stmt_Stmts"}_Stmts') } (_, simple_config, _) = krun(init_term) return pyk.splitConfigFrom(simple_config)
def insertDots(k): (config, subst) = pyk.splitConfigFrom(k) if pyk.isKSequence(subst['INSTRS_CELL']) and pyk.isKVariable(subst['INSTRS_CELL']['items'][-1]) and subst['INSTRS_CELL']['items'][-1]['name'].startswith('DotVar'): subst['INSTRS_CELL'] = KApply('#dotsRight', [KSequence(subst['INSTRS_CELL']['items'][0:-1])]) return pyk.substitute(config, subst)
def get_init_config(backend): init_term = {'format': 'KAST', 'version': 1, 'term': KConstant('noop')} (_, simple_config, _) = krunJson(init_term, backend) return pyk.splitConfigFrom(simple_config)
def run_tests(): global args testArgs = argparse.ArgumentParser(description='') testArgs.add_argument('files', metavar='N', type=str, nargs='+', help='') testArgs.add_argument('--coverage', action='store_true', help='Display test coverage data.') testArgs.add_argument('--log-level', choices=['none', 'per-file', 'per-step'], default='per-file') testArgs.add_argument('--verbose', action='store_true', help='') args = testArgs.parse_args() tests = args.files per_test_coverage = [] template_wasm_config = pyk.readKastTerm('src/elrond-runtime.loaded.json') cells = pyk.splitConfigFrom(template_wasm_config)[1] assert cells['K_CELL']['arity'] == 0 coverage = cov.Coverage() for test in tests: if args.verbose: print("Running test %s" % test) tmpdir = tempfile.mkdtemp(prefix="mandos_") if args.verbose: print("Intermediate test outputs stored in:\n%s" % tmpdir) initial_name = "0000_initial_config" with open('%s/%s' % (tmpdir, initial_name), 'w') as f: f.write(json.dumps(config_to_kast_term(template_wasm_config))) result_wasm_config = run_test_file(template_wasm_config, test, tmpdir, args) if args.coverage: end_config = result_wasm_config #pyk.readKastTerm(os.path.join(tmpdir, test_name)) collect_data_func = lambda entry: (int(entry['args'][0]['token']), int(entry['args'][1]['token'])) func_cov_filter_func = lambda term: 'label' in term and term[ 'label'] == 'fcd' func_cov = cov.get_coverage_data(end_config, 'COVEREDFUNCS_CELL', func_cov_filter_func, collect_data_func) block_cov_filter_func = lambda term: 'label' in term and term[ 'label'] == 'blockUid' block_cov = cov.get_coverage_data(end_config, 'COVEREDBLOCK_CELL', block_cov_filter_func, collect_data_func) mods = cov.get_module_filename_map(result_wasm_config) cov_data = { 'func_cov': func_cov, 'block_cov': block_cov, 'idx2file': mods } coverage.add_coverage(cov_data, unnamed='import') if args.verbose: print('See %s' % tmpdir) print() if args.coverage: text_modules = cov.insert_coverage_on_text_module( coverage, imports_mod_name='import') for module in text_modules: for line in module.splitlines(): print(line.decode('utf8'))