def visit_program(self, prgm): self.nodes = [] self.edges = [] self.jumps = [] self.labels = {} start = self.build_node("start") self.visit_stmts(prgm.stmts, start) # Generate jump edges for node, label in self.jumps: self.edges.extend([ Digraph.Edge(node, edge.to) for edge in self.edges if edge.frm == self.labels[label] ]) # Compute reachable nodes reachables = set() self.compute_reachable_nodes(start, reachables) # Remove all nodes and edges that are not reachable self.nodes = [n for n in self.nodes if n in reachables] self.edges = [e for e in self.edges if e.frm in reachables] return Digraph([start] + self.nodes, self.edges)
def build_resulting_graph(file_name, cfg, dead_blocks): dead_nodes = frozenset(node for block in dead_blocks for node in block.nodes) def dead_label(orig): return {'dead': True} if orig in dead_nodes else {} new_node_map = { node: Digraph.Node(node.name, ___orig=node, **dead_label(node)) for node in cfg.nodes } res_graph = Digraph([new_node_map[n] for n in cfg.nodes], [ Digraph.Edge(new_node_map[e.frm], new_node_map[e.to]) for e in cfg.edges ]) def print_orig(orig): if orig.data.node is not None: return ('<i>{}</i>'.format(html_render_node(orig.data.node)), ) return () def print_dead_code(value): return ('<font color="{}">{}</font>'.format('red', 'Dead node'), ) with open(file_name, 'w') as f: f.write( dot_printer.gen_dot(res_graph, [ dot_printer.DataPrinter('___orig', print_orig), dot_printer.DataPrinter("dead", print_dead_code) ]))
def visit_program(self, prgm): self.nodes = [] self.edges = [] self.jumps = [] self.labels = {} start = self.build_node("start") self.visit_stmts(prgm.stmts, start) # Generate jump edges for node, label in self.jumps: self.edges.extend([ Digraph.Edge(node, edge.to) for edge in self.edges if edge.frm == self.labels[label] ]) # Post process the CFG to find infer widening points and compute # the set of reachable nodes. visit_results = self.post_process_cfg(start) # Remove all nodes and edges that are not reachable self.nodes = [ n for n in self.nodes if visit_results[n] != CFGBuilder.NOT_VISITED ] self.edges = [ e for e in self.edges if visit_results[e.frm] != CFGBuilder.NOT_VISITED ] return Digraph([start] + self.nodes, self.edges)
def build_resulting_graph(file_name, cfg, null_derefs): def trace_id(trace): return str(trace) paths = defaultdict(list) for trace, derefed, precise in null_derefs: for node in trace: paths[node].append((trace, derefed, precise)) new_node_map = { node: Digraph.Node( node.name, ___orig=node, **{ trace_id(trace): (derefed, precise) for trace, derefed, precise in paths[node] } ) for node in cfg.nodes } res_graph = Digraph( [new_node_map[n] for n in cfg.nodes], [Digraph.Edge(new_node_map[e.frm], new_node_map[e.to]) for e in cfg.edges] ) def print_orig(orig): if orig.data.node is not None: return ( '<i>{}</i>'.format(html_render_node(orig.data.node)), ) return () def print_path_to_null_deref(value): derefed, precise = value qualifier = "" if precise else "potential " res_str = "path to {}null dereference of {}".format( qualifier, html_render_node(derefed) ) return ( '<font color="{}">{}</font>'.format('red', res_str), ) with open(file_name, 'w') as f: f.write(dot_printer.gen_dot(res_graph, [ dot_printer.DataPrinter('___orig', print_orig) ] + [ dot_printer.DataPrinter( trace_id(trace), print_path_to_null_deref ) for trace, _, _ in null_derefs ]))
def _build_resulting_graph(file_name, cfg, results, trace_domain, model): paths = defaultdict(list) var_set = { v for node, state in results.iteritems() for trace, values in state.iteritems() for v, _ in values.iteritems() } for node, state in results.iteritems(): for trace, values in state.iteritems(): paths[frozenset(trace)].append( Digraph.Node(node.name, ___orig=node, **{ v.name: value for v, value in values.iteritems() if not SyntheticVariable.is_purpose_of(v) })) edges = [] for trace, nodes in paths.iteritems(): for node in nodes: predecessors = [ n for t, ns in paths.iteritems() for n in ns if trace_domain.le(t, trace) if n.data.___orig in cfg.ancestors(node.data.___orig) ] for pred in predecessors: edges.append(Digraph.Edge(pred, node)) res_graph = Digraph([n for _, nodes in paths.iteritems() for n in nodes], edges) def print_orig(orig): if orig.data.node is not None: return ('<i>{}</i>'.format(_html_render_node(orig.data.node)), ) return () def print_result_builder(v): return lambda value: ("{} ∈".format(v.name), escape(model[v].domain.str(value))) with open(file_name, 'w') as f: f.write( dot_printer.gen_dot( res_graph, [dot_printer.DataPrinter('___orig', print_orig)] + [ dot_printer.DataPrinter(v.name, print_result_builder(v)) for v in var_set ]))
def build_resulting_graph(file_name, cfg, infeasibles): def trace_id(trace): return str(trace) paths = defaultdict(list) for trace, derefed, precise in infeasibles: for node in trace: paths[node].append((trace, derefed, precise)) new_node_map = { node: Digraph.Node(node.name, ___orig=node, **{ trace_id(trace): (derefed, precise) for trace, derefed, precise in paths[node] }) for node in cfg.nodes } res_graph = Digraph([new_node_map[n] for n in cfg.nodes], [ Digraph.Edge(new_node_map[e.frm], new_node_map[e.to]) for e in cfg.edges ]) def print_orig(orig): if orig.data.node is not None: return ('<i>{}</i>'.format(html_render_node(orig.data.node)), ) return () def print_path_to_infeasible_access(value): purpose, precise = value prefix = html_render_node(purpose.accessed_expr) qualifier = "" if precise else "potential " res_str = ("path to {}infeasible access {}.{} due to invalid " "condition on discriminant {}.{}").format( qualifier, prefix, escape(purpose.field_name), prefix, escape(purpose.discr_name)) return ('<font color="{}">{}</font>'.format('red', res_str), ) with open(file_name, 'w') as f: f.write( dot_printer.gen_dot( res_graph, [dot_printer.DataPrinter('___orig', print_orig)] + [ dot_printer.DataPrinter(trace_id(trace), print_path_to_infeasible_access) for trace, _, _ in infeasibles ]))
def export_schedule(schedule, export_path): """ Exports the given schedule as a dot graph. Each horizontally aligned elements can be ran in parallel. :param lalcheck.tools.scheduler.Schedule schedule: The schedule to export. :param str export_path: The path to the dot file to write. The .dot extension is appended here. """ nice_colors = [ '#093145', '#107896', '#829356', '#3C6478', '#43ABC9', '#B5C689', '#BCA136', '#C2571A', '#9A2617', '#F26D21', '#C02F1D', '#F58B4C', '#CD594A' ] def var_printer(var): name = str(var) color = nice_colors[hash(name) % len(nice_colors)] def colored(x): return '<font color="{}">{}</font>'.format(color, x) def printer(x): return ('<i>{}</i>'.format(colored(name)), colored(x)) return printer tasks = frozenset(task for batch in schedule.batches for task in batch) varset = frozenset(var for task in tasks for var in vars(task).keys()) task_to_node = { task: Digraph.Node(task.__class__.__name__, **vars(task)) for task in tasks } edges = [ Digraph.Edge(task_to_node[a], task_to_node[b]) for a in tasks for b in tasks if len( frozenset(a.provides().values()) & frozenset(b.requires().values())) > 0 ] digraph = Digraph(task_to_node.values(), edges) dot = gen_dot(digraph, [DataPrinter(var, var_printer(var)) for var in varset]) with open("{}.dot".format(export_path), 'w') as export_file: export_file.write(dot)
def register_and_link(self, froms, new_node): self.nodes.append(new_node) for f in froms: if f is not None: self.edges.append(Digraph.Edge(f, new_node))
def build_node(self, name, is_widening_point=False, orig_node=None): return Digraph.Node( name=self.fresh(name), is_widening_point=is_widening_point, node=orig_node )