#!/usr/bin/env python3 ''' usage: cbmc --json-ui --verbosity 4 | ./formatCBMCOutput.py ''' import sys, json, argparse from collections import defaultdict, OrderedDict #OrderedDict for removing duplicates NL = '\n' ABSOLUTE_PATHS = False def parse_source_location(array_info): source_loc = array_info['sourceLocation'] line_num, file_name = source_loc['line'], source_loc['file'] if ABSOLUTE_PATHS: working_dir = source_loc['workingDirectory'] file_name = f'{working_dir}/{file_name}' return f"{file_name}:{line_num}: note: " def parse_data(array_info): return array_info['data'] if 'data' in array_info else "?" def parse_assingment(array_info): result_str = [] result_str.append(parse_source_location(array_info)) if array_info['assignmentType'] == "actual-parameter": result_str.append(f"function_parameter_set_in:") if 'function' not in array_info['sourceLocation']: result_str.append(f"entry_point_function:") else: result_str.append(f"{array_info['sourceLocation']['function']}:") result_str.append( f"{array_info['sourceLocation']['line']}:{array_info['value']['name']}:{8*' '}{array_info['lhs']} = " ) if 'elements' in array_info['value']: result_str.append( f"{[parse_data(val['value']) for val in array_info['value']['elements']]}{NL}" ) else: result_str.append(f"{parse_data(array_info['value'])}{NL}") return ''.join(result_str) def parse_function(array_info): result_str = [] result_str.append(parse_source_location(array_info)) if 'function' not in array_info['sourceLocation']: result_str.append(f"from_entry_point_function:") else: result_str.append(f"from_{array_info['sourceLocation']['function']}:") result_str.append( f"{array_info['stepType']}:{array_info['function']['displayName']}{NL}") return ''.join(result_str) def parse_trace(trace_arr): result_str = [] for index, step in enumerate(trace_arr): if 'hidden' in step and step['hidden'] or \ 'internal' in step and step['internal'] or \ 'sourceLocation' not in step: continue if 'function' in step: result_str.append(parse_function(step)) elif 'assignmentType' in step: result_str.append(parse_assingment(step)) elif 'reason' in step: result_str.append( f"{parse_source_location(step)}{step['reason']}{NL}") return ''.join(list(OrderedDict.fromkeys(result_str))) #remove duplicates def parse_it(): errors = defaultdict(list) try: parsed = json.load(sys.stdin) except ValueError: print(f"Error: CBMC_WARNING:{NL}cbmc: fatal error: CBMC crashed") return errors if 'cProverStatus' not in parsed[-1]: print(f"Error: CBMC_WARNING:{NL}cbmc: fatal error: CBMC crashed") return errors if {'cProverStatus': 'success'} in parsed: return errors for result in parsed[-3]['result']: if result['status'] == "FAILURE": #and\ if 'sourceLocation' not in result['trace'][-1]: #memory leak detected\ file_name = '' fun_name = '' line_num = '' reason = result['description'] proprty = result['property'] else: source_loc = result['trace'][-1]['sourceLocation'] file_name = source_loc['file'] fun_name = source_loc['function'] line_num = source_loc['line'] if ABSOLUTE_PATHS: working_dir = source_loc['workingDirectory'] file_name = f'{working_dir}/{file_name}' info = result['trace'][-1] reason = info['reason'] proprty = info['property'] trace = parse_trace(result['trace']) errors[(file_name, fun_name)].append( (line_num, reason, proprty, trace)) return errors def print_it(error_dict): for file_and_func_name in error_dict.keys(): file_name, func_name = file_and_func_name for err in error_dict[file_and_func_name]: err_prefix = "Error: CBMC_WARNING:" print(f"{err_prefix}") line_num, proprty, trace = err[0], err[1], err[3] reason = err[2].split('.')[1] # add line number in which builtin function was called fi_na_li_nu = "" # function name and line number if "builtin" in file_name: builtin_lib_fun_name = file_name.replace('<','').replace('>','').split('-')[-1] file_name, line_num = tuple(list(filter( lambda line: (builtin_lib_fun_name in line and 'function-call' in line), trace.split('\n')))[0].split(':')[:2]) reason = f"in {func_name}: " + reason if file_name != '' and func_name != '': print(f"{file_name}: scope_hint: In function ‘{func_name}’:") print( f"{file_name}:{line_num}: error: {reason}: {proprty}{NL}{trace}") if __name__ == '__main__': parser = argparse.ArgumentParser(description='cbmc to csgrep conversion') parser.add_argument("-a", "--absolute-paths", action="store_true", help="make all paths absolute") arguments = parser.parse_args() ABSOLUTE_PATHS = arguments.absolute_paths print_it(parse_it())