3737class DFBScanAgent (Agent ):
3838 def __init__ (
3939 self ,
40- bug_type ,
41- is_reachable ,
42- project_path ,
43- language ,
44- ts_analyzer ,
45- model_name ,
46- temperature ,
47- call_depth ,
48- max_neural_workers = 30 ,
40+ bug_type : str ,
41+ is_reachable : bool ,
42+ project_path : str ,
43+ language : str ,
44+ ts_analyzer : TSAnalyzer ,
45+ model_name : str ,
46+ temperature : float ,
47+ call_depth : int ,
48+ max_neural_workers : int = 30 ,
4949 agent_id : int = 0 ,
5050 ) -> None :
5151 self .bug_type = bug_type
@@ -112,7 +112,9 @@ def __obtain_extractor(self) -> DFBScanExtractor:
112112 elif self .language == "Go" :
113113 if self .bug_type == "NPD" :
114114 return Go_NPD_Extractor (self .ts_analyzer )
115- return None
115+ raise NotImplementedError (
116+ f"Unsupported bug type: { self .bug_type } in { self .language } "
117+ )
116118
117119 def __update_worklist (
118120 self ,
@@ -174,21 +176,23 @@ def __update_worklist(
174176 if not is_CFL_reachable :
175177 continue
176178
177- for para in callee_function .paras :
178- if para .index == value .index :
179- delta_worklist .append (
180- (para , callee_function , new_call_context )
181- )
182- self .state .update_external_value_match (
183- (value , call_context ), set ({(para , new_call_context )})
184- )
179+ if callee_function .paras is not None :
180+ for para in callee_function .paras :
181+ if para .index == value .index :
182+ delta_worklist .append (
183+ (para , callee_function , new_call_context )
184+ )
185+ self .state .update_external_value_match (
186+ (value , call_context ),
187+ set ({(para , new_call_context )}),
188+ )
185189
186190 if value .label == ValueLabel .PARA :
187191 # Consider side-effect.
188192 # Example: the parameter *p is used in the function: p->f = null;
189193 # We need to consider the side-effect of p.
190- caller_function = self .ts_analyzer .get_all_caller_functions (function )
191- for caller_function in caller_function :
194+ caller_functions = self .ts_analyzer .get_all_caller_functions (function )
195+ for caller_function in caller_functions :
192196 new_call_context = copy .deepcopy (call_context )
193197 top_unmatched_context_label = (
194198 new_call_context .get_top_unmatched_context_label ()
@@ -442,9 +446,13 @@ def start_scan_sequential(self) -> None:
442446 ret .name ,
443447 ret .line_number - start_function .start_line_number + 1 ,
444448 )
445- for ret in start_function .retvals
449+ for ret in (
450+ start_function .retvals
451+ if start_function .retvals is not None
452+ else []
453+ )
446454 ]
447- input = IntraDataFlowAnalyzerInput (
455+ df_input = IntraDataFlowAnalyzerInput (
448456 start_function ,
449457 start_value ,
450458 sink_values ,
@@ -453,20 +461,22 @@ def start_scan_sequential(self) -> None:
453461 )
454462
455463 # Invoke the intra-procedural data-flow analysis
456- output = self .intra_dfa .invoke (input )
457- if output is None :
464+ df_output = self .intra_dfa .invoke (
465+ df_input , IntraDataFlowAnalyzerOutput
466+ )
467+ if df_output is None :
458468 continue
459469
460- for path_index in range (len (output .reachable_values )):
470+ for path_index in range (len (df_output .reachable_values )):
461471 reachable_values_in_single_path = set ([])
462- for value in output .reachable_values [path_index ]:
472+ for value in df_output .reachable_values [path_index ]:
463473 reachable_values_in_single_path .add ((value , call_context ))
464474 self .state .update_reachable_values_per_path (
465475 (start_value , call_context ), reachable_values_in_single_path
466476 )
467477
468478 delta_worklist = self .__update_worklist (
469- input , output , call_context , path_index
479+ df_input , df_output , call_context , path_index
470480 )
471481 worklist .extend (delta_worklist )
472482
@@ -479,20 +489,22 @@ def start_scan_sequential(self) -> None:
479489 continue
480490
481491 for buggy_path in self .state .potential_buggy_paths [src_value ].values ():
482- input = PathValidatorInput (
492+ pv_input = PathValidatorInput (
483493 self .bug_type ,
484494 buggy_path ,
485495 {
486496 value : self .ts_analyzer .get_function_from_localvalue (value )
487497 for value in buggy_path
488498 },
489499 )
490- output : PathValidatorOutput = self .path_validator .invoke (input )
500+ pv_output = self .path_validator .invoke (
501+ pv_input , PathValidatorOutput
502+ )
491503
492- if output is None :
504+ if pv_output is None :
493505 continue
494506
495- if output .is_reachable :
507+ if pv_output .is_reachable :
496508 relevant_functions = {}
497509 for value in buggy_path :
498510 function = self .ts_analyzer .get_function_from_localvalue (
@@ -505,7 +517,7 @@ def start_scan_sequential(self) -> None:
505517 self .bug_type ,
506518 src_value ,
507519 relevant_functions ,
508- output .explanation_str ,
520+ pv_output .explanation_str ,
509521 )
510522 self .state .update_bug_report (bug_report )
511523
@@ -606,28 +618,30 @@ def __process_src_value(self, src_value: Value) -> None:
606618
607619 ret_values = [
608620 (ret .name , ret .line_number - start_function .start_line_number + 1 )
609- for ret in start_function .retvals
621+ for ret in (
622+ start_function .retvals if start_function .retvals is not None else []
623+ )
610624 ]
611- input = IntraDataFlowAnalyzerInput (
625+ df_input = IntraDataFlowAnalyzerInput (
612626 start_function , start_value , sink_values , call_statements , ret_values
613627 )
614628
615629 # Invoke the intra-procedural data-flow analysis
616- output = self .intra_dfa .invoke (input )
630+ df_output = self .intra_dfa .invoke (df_input , IntraDataFlowAnalyzerOutput )
617631
618- if output is None :
632+ if df_output is None :
619633 continue
620634
621- for path_index in range (len (output .reachable_values )):
635+ for path_index in range (len (df_output .reachable_values )):
622636 reachable_values_in_single_path = set ([])
623- for value in output .reachable_values [path_index ]:
637+ for value in df_output .reachable_values [path_index ]:
624638 reachable_values_in_single_path .add ((value , call_context ))
625639 self .state .update_reachable_values_per_path (
626640 (start_value , call_context ), reachable_values_in_single_path
627641 )
628642
629643 delta_worklist = self .__update_worklist (
630- input , output , call_context , path_index
644+ df_input , df_output , call_context , path_index
631645 )
632646 worklist .extend (delta_worklist )
633647
@@ -645,30 +659,36 @@ def __process_src_value(self, src_value: Value) -> None:
645659 for value in buggy_path
646660 }
647661
648- relevant_functions = values_to_functions .values ()
662+ functions : Set [Function ] = set ()
663+ for func in values_to_functions .values ():
664+ if func is not None :
665+ functions .add (func )
649666
650- if self .state .check_existence (src_value , relevant_functions ):
667+ if self .state .check_existence (src_value , functions ):
651668 continue
652669
653- input = PathValidatorInput (
670+ pv_input = PathValidatorInput (
654671 self .bug_type ,
655672 buggy_path ,
656673 values_to_functions ,
657674 )
658- output : PathValidatorOutput = self .path_validator .invoke (input )
675+ pv_output = self .path_validator .invoke (pv_input , PathValidatorOutput )
659676
660- if output is None :
677+ if pv_output is None :
661678 continue
662679
663- if output .is_reachable :
680+ if pv_output .is_reachable :
664681 relevant_functions = {}
665682 for value in buggy_path :
666683 function = self .ts_analyzer .get_function_from_localvalue (value )
667684 if function is not None :
668685 relevant_functions [function .function_id ] = function
669686
670687 bug_report = BugReport (
671- self .bug_type , src_value , relevant_functions , output .explanation_str
688+ self .bug_type ,
689+ src_value ,
690+ relevant_functions ,
691+ pv_output .explanation_str ,
672692 )
673693 self .state .update_bug_report (bug_report )
674694 bug_report_dict = {
0 commit comments