def test_assign_weights_wo_defaults(self): # Arrange target = CallGraph( source='/tmp', graph=self._build_graph(), load_errors=list(), ) weights = { "base": { "call": 125, "return": 75 }, "dangerous": 35, "defense": -30, "tested": -25, "vulnerable": 35 } expected = { ('main', 'read'): 100, ('read', 'main'): 50, ('main', 'write'): 135, ('write', 'main'): 50, ('main', 'parse'): 125, ('parse', 'main'): 50, ('main', 'analyze'): 135, ('analyze', 'main'): 50, ('main', 'memalloc'): 140, ('memalloc', 'main'): 50, ('read', 'readfile'): 100, ('readfile', 'read'): 50, ('read', 'validate'): 70, ('validate', 'read'): 50, ('write', 'writefile'): 100, ('writefile', 'write'): 85, ('parse', 'parsefile'): 160, ('parsefile', 'parse'): 75, ('analyze', 'analyzefile'): 125, ('analyzefile', 'analyze'): 85 } # Act target.assign_weights(weights) actual = nx.get_edge_attributes(target.call_graph, 'weight') # Assert self.assertCountEqual(expected, actual) for i in expected: self.assertEqual(expected[i], actual[i], msg=i)
def test_call_graph_w_fragmentize(self): # Arrange # a -- b e -- f -- g # | | # | | # d -- c h -- i j graph = nx.DiGraph() graph.add_nodes_from( ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']) graph.add_edges_from([('a', 'b'), ('b', 'a'), ('b', 'c'), ('c', 'b'), ('c', 'd'), ('d', 'c'), ('d', 'a'), ('a', 'd'), ('e', 'f'), ('f', 'e'), ('f', 'g'), ('g', 'f'), ('h', 'i'), ('i', 'h')]) expected = nx.DiGraph() expected.add_nodes_from(['a', 'b', 'c', 'd']) expected.add_edges_from([('a', 'b'), ('b', 'a'), ('b', 'c'), ('c', 'b'), ('c', 'd'), ('d', 'c'), ('d', 'a'), ('a', 'd')]) # Act actual = CallGraph(source='/tmp', graph=graph, load_errors=list(), fragmentize=True) # Assert self.assertEqual(4, actual.num_fragments) self.assertEqual(0.4, actual.monolithicity) self.assertCountEqual(expected.nodes(), [i for (i, _) in actual.nodes]) self.assertCountEqual(expected.edges(), [(i, j) for (i, j, _) in actual.edges])
def setUp(self): self.target = CallGraph.from_loader( CflowLoader( os.path.join( os.path.dirname(os.path.realpath(__file__)), 'helloworld/cflow.callgraph.r.txt' ), True ) )
def setUp(self): self.target = CallGraph.from_loader( CflowLoader( os.path.join( os.path.dirname(os.path.realpath(__file__)), 'helloworld' ), False ) )
def setUp(self): self.target = CallGraph.from_loader( CflowLoader( os.path.join( os.path.dirname(os.path.realpath(__file__)), 'helloworld/cflow.callgraph.txt' ), False ), granularity=Granularity.FILE )
def setUp(self): self.target = CallGraph.from_merge( CallGraph.from_loader( CflowLoader( os.path.join( os.path.dirname(os.path.realpath(__file__)), 'helloworld/cflow.callgraph.r.txt' ), True ), granularity=Granularity.FILE ), CallGraph.from_loader( GprofLoader( os.path.join( os.path.dirname(os.path.realpath(__file__)), 'helloworld/gprof.callgraph.txt' ) ), granularity=Granularity.FILE ) )
def test_assign_weights_w_defaults(self): # Arrange target = CallGraph( source='/tmp', graph=self._build_graph(), load_errors=list(), ) expected = { ('main', 'read'): 75, ('read', 'main'): 25, ('main', 'write'): 100, ('write', 'main'): 25, ('main', 'parse'): 100, ('parse', 'main'): 25, ('main', 'analyze'): 100, ('analyze', 'main'): 25, ('main', 'memalloc'): 100, ('memalloc', 'main'): 25, ('read', 'readfile'): 75, ('readfile', 'read'): 25, ('read', 'validate'): 50, ('validate', 'read'): 25, ('write', 'writefile'): 75, ('writefile', 'write'): 50, ('parse', 'parsefile'): 125, ('parsefile', 'parse'): 50, ('analyze', 'analyzefile'): 100, ('analyzefile', 'analyze'): 50 } # Act target.assign_weights() actual = nx.get_edge_attributes(target.call_graph, 'weight') # Assert self.assertCountEqual(expected, actual) for i in expected: self.assertEqual(expected[i], actual[i], msg=i)
def setUp(self): call_graph = CallGraph.from_loader( CflowLoader( os.path.join(os.path.dirname(os.path.realpath(__file__)), 'helloworld'))) self.formatter = HtmlFormatter(call_graph) self.formatter_output_file = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'helloworld/formatter.output.html') self.formatter_summary_file = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'helloworld/formatter.summary.html')
def setUp(self): call_graph = CallGraph.from_loader( CflowLoader( os.path.join( os.path.dirname(os.path.realpath(__file__)), 'helloworld' ) ) ) self.formatter = HtmlFormatter(call_graph) self.formatter_output_file = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'helloworld/formatter.output.html' ) self.formatter_summary_file = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'helloworld/formatter.summary.html' )
def test_sanitize(self): # Arrange expected_nodes = [ Call('', './src/helloworld.c', Env.C, Gran.FILE), Call('', './src/greetings.c', Env.C, Gran.FILE), ] expected_edges = [ (Call('', './src/helloworld.c', Env.C, Gran.FILE), Call('', './src/helloworld.c', Env.C, Gran.FILE)), (Call('', './src/greetings.c', Env.C, Gran.FILE), Call('', './src/helloworld.c', Env.C, Gran.FILE)), (Call('', './src/helloworld.c', Env.C, Gran.FILE), Call('', './src/greetings.c', Env.C, Gran.FILE)), (Call('', './src/greetings.c', Env.C, Gran.FILE), Call('', './src/greetings.c', Env.C, Gran.FILE)) ] # Act graph = CallGraph.from_loader(CflowLoader( os.path.join(os.path.dirname(os.path.realpath(__file__)), 'helloworld/cflow.callgraph.r.mod.txt'), True), granularity=Gran.FILE) edges = [(caller, callee) for (caller, callee, _) in graph.edges] all_edges_found = all([c in edges for c in expected_edges]) nodes = [n for (n, _) in graph.nodes] all_nodes_found = (all([n in nodes for n in expected_nodes]) and all([n in expected_nodes for n in nodes])) # Assert self.assertEqual(len(expected_nodes), len(nodes)) self.assertTrue(all_nodes_found) self.assertEqual(len(expected_edges), len(edges)) self.assertTrue(all_edges_found)
def test_fix(self): # Arrange target = CallGraph.from_loader( CflowLoader( os.path.join( os.path.dirname(os.path.realpath(__file__)), 'helloworld/cflow.callgraph.r.mod.txt' ), True ) ) _target = copy.deepcopy(target) reference = CallGraph.from_loader( GprofLoader( os.path.join( os.path.dirname(os.path.realpath(__file__)), 'helloworld/gprof.callgraph.txt' ) ) ) expected = { 'before': Call('GreeterSayHi', '', Environments.C), 'after': Call('GreeterSayHi', './src/helloworld.c', Environments.C) } # Act utilities.fix(target, using=reference) actual = { 'before': next( i for (i, _) in _target.nodes if i.function_name == 'GreeterSayHi' ), 'after': next( i for (i, _) in target.nodes if i.function_name == 'GreeterSayHi' ) } # Assert self.assertEqual(expected['before'], actual['before']) self.assertEqual(expected['after'], actual['after']) # Asserting if node attributes got carried over self.assertCountEqual( [ attrs for (i, attrs) in _target.nodes if i == expected['before'] ], [ attrs for (i, attrs) in target.nodes if i == expected['after'] ] ) # Asserting if edge attributes got carried over self.assertCountEqual( [ attrs for (i, j, attrs) in _target.edges if i == expected['before'] or j == expected['before'] ], [ attrs for (i, j, attrs) in target.edges if i == expected['after'] or j == expected['after'] ], ) # Asserting if OTHER nodes and their attributes got carried over self.assertCountEqual( [ (i, attrs) for (i, attrs) in _target.nodes if i != expected['before'] ], [ (i, attrs) for (i, attrs) in target.nodes if i != expected['after'] ] ) # Asserting if OTHER edges and their attributes got carried over self.assertCountEqual( [ (i, j, attrs) for (i, j, attrs) in _target.edges if i != expected['before'] and j != expected['before'] ], [ (i, j, attrs) for (i, j, attrs) in target.edges if i != expected['after'] and j != expected['after'] ], )
def main(): args = parse_args() call_graph = None if args.javacg: loader = JavaCGLoader(args.javacg, args.apppackages) call_graph = CallGraph.from_loader(loader) else: cflow_loader = None gprof_loader = None if args.cflow: if not os.path.exists(args.cflow): raise Exception('{} not found.'.format(args.cflow)) else: cflow_loader = CflowLoader(args.cflow, reverse=args.reverse) if args.gprof: if not os.path.exists(args.gprof): raise Exception('{} not found.'.format(args.gprof)) else: if os.path.isdir(args.gprof): sources = [ os.path.join(args.gprof, filename) for filename in os.listdir(args.gprof) if os.path.isfile(os.path.join(args.gprof, filename)) ] gprof_loader = MultigprofLoader(sources, processes=args.processes) else: gprof_loader = GprofLoader(args.gprof) if cflow_loader and gprof_loader: call_graph = CallGraph.from_merge( CallGraph.from_loader(cflow_loader, granularity=args.granularity), CallGraph.from_loader(gprof_loader, granularity=args.granularity)) elif cflow_loader: call_graph = CallGraph.from_loader(cflow_loader, granularity=args.granularity) elif gprof_loader: call_graph = CallGraph.from_loader(gprof_loader, granularity=args.granularity) if args.output: (name, extension) = os.path.splitext(args.output) output_format = extension.replace('.', '') if output_format not in FORMATTERS: output_format = 'txt' formatter = FORMATTERS[output_format](call_graph) with open(args.output, 'w') as file_: if args.verbose: file_.write(formatter.write_output()) else: file_.write(formatter.write_summary()) else: formatter = FORMATTERS['txt'](call_graph) if args.verbose: sys.stdout.write(formatter.write_output()) else: sys.stdout.write(formatter.write_summary()) if args.showerrors and call_graph.load_errors: sys.stdout.write('Parse Errors\n') sys.stdout.write('============\n') for error in call_graph.load_errors: sys.stdout.write(error)
def stat(**options): cflow_path = options.get('cflow_path', None) gprof_path = options.get('gprof_path', None) num_processes = options.get('num_processes') output = options.get('output', False) threshold = options.get('threshold', None) subject = options.get('subject', None) revision = options.get('revision', None) if subject not in settings.ENABLED_SUBJECTS: raise CommandError('Subject {0} is not enabled'.format(subject)) cflow_loader = None gprof_loader = None cflow_call_graph = None gprof_call_graph = None begin = datetime.datetime.now() if cflow_path: fragmentize = False if not gprof_path: fragmentize = True print('Loading cflow call graph') cflow_loader = CflowLoader(cflow_path, reverse=True) cflow_call_graph = CallGraph.from_loader(cflow_loader, fragmentize) if gprof_path: fragmentize = False if not cflow_path: fragmentize = True print('Loading gprof call graph') if os.path.isdir(gprof_path): sources = [ os.path.join(gprof_path, file_name) for file_name in os.listdir(gprof_path) if 'txt' in file_name ] os.environ['DEBUG'] = '1' gprof_loader = MultigprofLoader(sources, processes=num_processes) gprof_call_graph = CallGraph.from_loader(gprof_loader, fragmentize) else: gprof_loader = GprofLoader(gprof_path, reverse=False) gprof_call_graph = CallGraph.from_loader(gprof_loader, fragmentize) end = datetime.datetime.now() call_graph = None if cflow_call_graph and gprof_call_graph: if 'DEBUG' in os.environ: print() print('Merging cflow and gprof call graphs') call_graph = CallGraph.from_merge(cflow_call_graph, gprof_call_graph, fragmentize=True) elif cflow_call_graph: call_graph = cflow_call_graph elif gprof_call_graph: call_graph = gprof_call_graph if not call_graph: print('Nothing to stat. Exiting.') sys.exit(0) print('Load completed in {0:.2f} seconds'.format( (end - begin).total_seconds())) print('#' * 50) print(' Call Graph Statistics') print('#' * 50) print(' Nodes {0}'.format(len(call_graph.nodes))) print(' Edges {0}'.format(len(call_graph.edges))) print(' Entry Points {0}'.format(len(call_graph.entry_points))) print(' Exit Points {0}'.format(len(call_graph.exit_points))) print(' Dangerous {0}'.format( len(nx.get_node_attributes(call_graph.call_graph, 'dangerous')))) print(' Monolithicity {0:4f}'.format(call_graph.monolithicity)) print(' Fragments {0}'.format(call_graph.num_fragments)) print('#' * 50) if output: generate(subject, revision, call_graph, threshold, num_processes)
def setUp(self): self.target = CallGraph.from_loader( CflowLoader( os.path.join(os.path.dirname(os.path.realpath(__file__)), 'helloworld'), False))