(self, all_funcs_completed=False)
Iteratively analyze all changed functions, update their returning attribute, until a fix-point is reached (i.e.
        no new returning/not-returning functions are found).

        :return: None
Iteratively analyze all changed functions, update their returning attribute, until a fix-point is reached (i.e.
        no new returning/not-returning functions are found).
Iteratively analyze all changed functions update their returning attribute until a fix - point is reached ( i . e . no new returning / not - returning functions are found ) .
def _analyze_all_function_features(self, all_funcs_completed=False):
        """
        Iteratively analyze all changed functions, update their returning attribute, until a fix-point is reached (i.e.
        no new returning/not-returning functions are found).

        :return: None
        """

        while True:
            new_changes = self._iteratively_analyze_function_features(all_funcs_completed=all_funcs_completed)
            new_returning_functions = new_changes['functions_return']
            new_not_returning_functions = new_changes['functions_do_not_return']

            if not new_returning_functions and not new_not_returning_functions:
                break

            for returning_function in new_returning_functions:
                self._pending_jobs.add_returning_function(returning_function.addr)
                if returning_function.addr in self._function_returns:
                    for fr in self._function_returns[returning_function.addr]:
                        # Confirm them all
                        if not self.kb.functions.contains_addr(fr.caller_func_addr):
                            # FIXME: A potential bug might arise here. After post processing (phase 2), if the function
                            # specified by fr.caller_func_addr has been merged to another function during phase 2, we
                            # will simply skip this FunctionReturn here. It might lead to unconfirmed fake_ret edges
                            # in the newly merged function. Fix this bug in the future when it becomes an issue.
                            continue

                        if self.kb.functions.get_by_addr(fr.caller_func_addr).returning is not True:
                            self._updated_nonreturning_functions.add(fr.caller_func_addr)

                        return_to_node = self._nodes.get(fr.return_to, None)
                        if return_to_node is None:
                            return_to_snippet = self._to_snippet(addr=fr.return_to, base_state=self._base_state)
                        else:
                            return_to_snippet = self._to_snippet(cfg_node=self._nodes[fr.return_to])

                        self.kb.functions._add_return_from_call(fr.caller_func_addr, fr.callee_func_addr,
                                                                return_to_snippet)

                    del self._function_returns[returning_function.addr]

            for nonreturning_function in new_not_returning_functions:
                self._pending_jobs.add_nonreturning_function(nonreturning_function.addr)
                if nonreturning_function.addr in self._function_returns:
                    for fr in self._function_returns[nonreturning_function.addr]:
                        # Remove all pending FakeRet edges
                        if self.kb.functions.contains_addr(fr.caller_func_addr) and \
                                self.kb.functions.get_by_addr(fr.caller_func_addr).returning is not True:
                            self._updated_nonreturning_functions.add(fr.caller_func_addr)

                    del self._function_returns[nonreturning_function.addr]
def _analyze_all_function_features ( self , all_funcs_completed = False ) : while True : new_changes = self . _iteratively_analyze_function_features ( all_funcs_completed = all_funcs_completed ) new_returning_functions = new_changes [ 'functions_return' ] new_not_returning_functions = new_changes [ 'functions_do_not_return' ] if not new_returning_functions and not new_not_returning_functions : break for returning_function in new_returning_functions : self . _pending_jobs . add_returning_function ( returning_function . addr ) if returning_function . addr in self . _function_returns : for fr in self . _function_returns [ returning_function . addr ] : # Confirm them all if not self . kb . functions . contains_addr ( fr . caller_func_addr ) : # FIXME: A potential bug might arise here. After post processing (phase 2), if the function # specified by fr.caller_func_addr has been merged to another function during phase 2, we # will simply skip this FunctionReturn here. It might lead to unconfirmed fake_ret edges # in the newly merged function. Fix this bug in the future when it becomes an issue. continue if self . kb . functions . get_by_addr ( fr . caller_func_addr ) . returning is not True : self . _updated_nonreturning_functions . add ( fr . caller_func_addr ) return_to_node = self . _nodes . get ( fr . return_to , None ) if return_to_node is None : return_to_snippet = self . _to_snippet ( addr = fr . return_to , base_state = self . _base_state ) else : return_to_snippet = self . _to_snippet ( cfg_node = self . _nodes [ fr . return_to ] ) self . kb . functions . _add_return_from_call ( fr . caller_func_addr , fr . callee_func_addr , return_to_snippet ) del self . _function_returns [ returning_function . addr ] for nonreturning_function in new_not_returning_functions : self . _pending_jobs . add_nonreturning_function ( nonreturning_function . addr ) if nonreturning_function . addr in self . _function_returns : for fr in self . _function_returns [ nonreturning_function . addr ] : # Remove all pending FakeRet edges if self . kb . functions . contains_addr ( fr . caller_func_addr ) and self . kb . functions . get_by_addr ( fr . caller_func_addr ) . returning is not True : self . _updated_nonreturning_functions . add ( fr . caller_func_addr ) del self . _function_returns [ nonreturning_function . addr ]