Skip to content

Commit a82c4f6

Browse files
core: frontends: cpp: support mixing C files (#1959)
* core: frontends: cpp: support mixing C files Add support for mixing C files in cpp projects Signed-off-by: David Korczynski <[email protected]> * nit Signed-off-by: David Korczynski <[email protected]> * nit Signed-off-by: David Korczynski <[email protected]> * nit Signed-off-by: David Korczynski <[email protected]> --------- Signed-off-by: David Korczynski <[email protected]>
1 parent 2bd5717 commit a82c4f6

File tree

1 file changed

+77
-21
lines changed

1 file changed

+77
-21
lines changed

src/fuzz_introspector/frontends/frontend_cpp.py

Lines changed: 77 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ def _extract_information(self):
187187
# Extract function name and return type
188188
name_node = self.root.child_by_field_name('declarator')
189189
self.sig = name_node.text.decode()
190+
logger.debug('Extracting information for %s', self.sig)
190191
param_list_node = None
191192
for child in name_node.children:
192193
if 'identifier' in child.type:
@@ -219,9 +220,44 @@ def _extract_information(self):
219220
full_name = new_parent.child_by_field_name(
220221
'name').text.decode() + '::' + full_name
221222
tmp_root = new_parent
222-
logger.debug('Full function scope: %s', full_name)
223-
full_name = full_name + self.root.child_by_field_name(
224-
'declarator').child_by_field_name('declarator').text.decode()
223+
logger.debug('Full function scope not from name: %s', full_name)
224+
225+
tmp_name = ''
226+
tmp_node = self.root.child_by_field_name('declarator')
227+
scope_to_add = ''
228+
while True:
229+
if tmp_node is None:
230+
break
231+
if tmp_node.child_by_field_name('scope') is not None:
232+
scope_to_add = tmp_node.child_by_field_name(
233+
'scope').text.decode() + '::'
234+
235+
if tmp_node.type == 'identifier':
236+
tmp_name = tmp_node.text.decode()
237+
break
238+
if tmp_node.child_by_field_name(
239+
'name') is not None and tmp_node.child_by_field_name(
240+
'name').type == 'identifier':
241+
tmp_name = tmp_node.child_by_field_name('name').text.decode()
242+
tmp_node = tmp_node.child_by_field_name('declarator')
243+
if tmp_name:
244+
logger.debug('Assigning name')
245+
full_name = full_name + scope_to_add + tmp_name
246+
else:
247+
logger.debug('Assigning name as signature')
248+
full_name = self.sig
249+
250+
# try:
251+
# full_name = full_name + self.root.child_by_field_name(
252+
# 'declarator').child_by_field_name('declarator').child_by_field_name('declarator').text.decode()
253+
# except:
254+
# try:
255+
# full_name = full_name + self.root.child_by_field_name(
256+
# 'declarator').child_by_field_name('declarator').text.decode()
257+
# except:
258+
259+
# This can happen for e.g. operators
260+
# full_name = self.sig
225261
logger.debug('Full function name: %s', full_name)
226262
self.name = full_name
227263
logger.info('Done walking')
@@ -416,6 +452,10 @@ def _process_callsites(self, stmt: Node,
416452
var_type = ''
417453
var_type_obj = stmt.child_by_field_name('type')
418454

455+
if var_type_obj.type == 'primitive_type' or var_type_obj.type == 'sized_type_specifier':
456+
logger.debug('Skipping.')
457+
return []
458+
419459
while True:
420460
if var_type_obj is None:
421461
return []
@@ -446,29 +486,31 @@ def _process_callsites(self, stmt: Node,
446486
# the name of the constructor.
447487
cls = f'{var_type}::{var_type.rsplit("::")[-1]}'
448488
logger.debug('Trying to find class %s', cls)
449-
added = False
489+
# added = False
450490
if cls in project.all_functions:
451491
logger.debug('Adding callsite')
452-
added = True
492+
# added = True
453493
callsites.append(
454494
(cls, stmt.byte_range[1], stmt.start_point.row + 1))
455-
if not added:
456-
logger.debug('Trying a hacky match.')
457-
# Hack to make sure we add in case our analysis of contructors was
458-
# wrong. TODO(David) fix.
459-
cls = var_type
460-
if cls in project.all_functions:
461-
logger.debug('Adding callsite')
462-
added = True
463-
callsites.append((cls, stmt.byte_range[1],
464-
stmt.start_point.row + 1))
465-
466-
while var_name.type not in [
495+
# if not added:
496+
# logger.debug('Trying a hacky match.')
497+
# # Hack to make sure we add in case our analysis of contructors was
498+
# # wrong. TODO(David) fix.
499+
# cls = var_type
500+
# if cls in project.all_functions:
501+
# logger.debug('Adding callsite')
502+
# added = True
503+
# callsites.append((cls, stmt.byte_range[1],
504+
# stmt.start_point.row + 1))
505+
while var_name is not None and var_name.type not in [
467506
'identifier', 'qualified_identifier', 'pointer_declarator',
468507
'array_declarator', 'reference_declarator'
469508
]:
470509
var_name = var_name.child_by_field_name('declarator')
471510

511+
if var_name is None:
512+
return []
513+
472514
result = self._extract_pointer_array_from_type(var_name)
473515
pcount, acount, var_name = result
474516
var_type = f'{var_type}{"*" * pcount}{"[]" * acount}'
@@ -535,8 +577,10 @@ def dump_module_logic(self,
535577
# Process all project functions
536578
func_list = []
537579
for func in self.all_functions.values():
580+
logger.debug('Iterating %s', func.name)
581+
logger.debug('Extracing callsites')
538582
func.extract_callsites(self)
539-
583+
logger.debug('Done extracting callsites')
540584
func_dict: dict[str, Any] = {}
541585
func_dict['functionName'] = func.name
542586
func_dict['functionSourceFile'] = func.parent_source.source_file
@@ -556,7 +600,9 @@ def dump_module_logic(self,
556600
func_dict['returnType'] = func.return_type
557601
func_dict['BranchProfiles'] = []
558602
func_dict['Callsites'] = func.detailed_callsites
603+
logger.debug('Calculating function uses')
559604
func_dict['functionUses'] = self.calculate_function_uses(func.name)
605+
logger.debug('Getting function depth')
560606
func_dict['functionDepth'] = self.calculate_function_depth(func)
561607
func_dict['constantsTouched'] = []
562608
func_dict['BBCount'] = 0
@@ -567,6 +613,7 @@ def dump_module_logic(self,
567613
reached.add(cs_dst)
568614
func_dict['functionsReached'] = list(reached)
569615

616+
logger.debug('Done')
570617
func_list.append(func_dict)
571618

572619
if func_list:
@@ -608,10 +655,17 @@ def extract_calltree(self,
608655

609656
func_node = None
610657
if function:
611-
func_node = get_function_node(function, self.all_functions)
658+
if source_code:
659+
logger.debug('Using source code var to extract node')
660+
func_node = source_code.get_function_node(function)
661+
else:
662+
logger.debug('Extracting node using lookup table.')
663+
func_node = get_function_node(function, self.all_functions)
612664
if func_node:
665+
logger.debug('Found function node')
613666
func_name = func_node.name
614667
else:
668+
logger.debug('Found no function node')
615669
func_name = function
616670
else:
617671
return ''
@@ -631,13 +685,14 @@ def extract_calltree(self,
631685

632686
visited_functions.add(function)
633687
for cs, line in func_node.base_callsites:
688+
logger.debug('Callsites: %s', cs)
634689
line_to_print += self.extract_calltree(
635690
source_file=source_code.source_file,
636691
function=cs,
637692
visited_functions=visited_functions,
638693
depth=depth + 1,
639694
line_number=line)
640-
695+
logger.debug('Done')
641696
return line_to_print
642697

643698
def get_reachable_functions(self,
@@ -793,7 +848,8 @@ def capture_source_files_in_tree(directory_tree):
793848
"""Captures source code files in a given directory."""
794849
language_files = []
795850
language_extensions = [
796-
'.cpp', '.cc', '.c++', '.cxx', '.h', '.hpp', '.hh', '.hxx', '.inl'
851+
'.c', '.cpp', '.cc', '.c++', '.cxx', '.h', '.hpp', '.hh', '.hxx',
852+
'.inl'
797853
]
798854
exclude_directories = [
799855
'build', 'target', 'tests', 'node_modules', 'aflplusplus', 'honggfuzz',

0 commit comments

Comments
 (0)