prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Strange successors of the return block of a function
  I'm analysing a MIPS binary when facing the problem.
  
  The problem exists in the funcition `do_ssc`.
  
  In the following block which has a return statement
  ![image](https://user-images.githubusercontent.com/8875073/69912053-4fb60900-145f-11ea-9152-4026aab7f033.png)
  
  When I run `node.successors` I got
  ```
  In [103]: end.successors                                                                                              
  Out[103]: 
  [<CFGNode 0x40a7a8[28]>,
   <CFGNode do_ssc+0x12c [28]>,
   <CFGNode do_ssc+0x4c4 [28]>,
   <CFGNode do_ssc+0x45c [24]>,
   <CFGNode do_ssc+0x2a8 [24]>]
  ```
  Their addresses are `0x40a7a8`, `0x40a33c`, `0x40a6d4` and `0x40a4b8` respectively.
  
  I know the cfg of angr is interfunctional, however, only `0x40a7a8` is an caller of `do_ssc`.
  
  May I know why other threes exist?
  
  
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py`
  Content:
  ```
  1 
  2 import logging
  3 
  4 import pyvex
  5 import archinfo
  6 
  7 
  8 from .... import options, BP_BEFORE
  9 from ....blade import Blade
  10 from ....annocfg import AnnotatedCFG
  11 from ....exploration_techniques import Slicecutor
  12 
  13 from .resolver import IndirectJumpResolver
  14 
  15 
  16 l = logging.getLogger(name=__name__)
  17 
  18 
  19 class MipsElfFastResolver(IndirectJumpResolver):
  20     def __init__(self, project):
  21         super(MipsElfFastResolver, self).__init__(project, timeless=True)
  22 
  23     def filter(self, cfg, addr, func_addr, block, jumpkind):
  24         if not isinstance(self.project.arch, (archinfo.ArchMIPS32, archinfo.ArchMIPS64, )):
  25             return False
  26         return True
  27 
  28     def resolve(self, cfg, addr, func_addr, block, jumpkind):
  29         """
  30         Resolves the indirect jump in MIPS ELF binaries where all external function calls are indexed using gp.
  31 
  32         :param cfg: A CFG instance.
  33         :param int addr: IRSB address.
  34         :param int func_addr: The function address.
  35         :param pyvex.IRSB block: The IRSB.
  36         :param str jumpkind: The jumpkind.
  37         :return: If it was resolved and targets alongside it
  38         :rtype: tuple
  39         """
  40 
  41         project = self.project
  42 
  43         b = Blade(cfg.graph, addr, -1, cfg=cfg, project=project, ignore_sp=True, ignore_bp=True,
  44                   ignored_regs=('gp',)
  45                   )
  46 
  47         sources = [n for n in b.slice.nodes() if b.slice.in_degree(n) == 0]
  48         if not sources:
  49             return False, []
  50 
  51         source = sources[0]
  52         source_addr = source[0]
  53         annotated_cfg = AnnotatedCFG(project, None, detect_loops=False)
  54         annotated_cfg.from_digraph(b.slice)
  55 
  56         state = project.factory.blank_state(addr=source_addr, mode="fastpath",
  57                                             remove_options=options.refs
  58                                             )
  59         func = cfg.kb.functions.function(addr=func_addr)
  60 
  61         gp_offset = project.arch.registers['gp'][0]
  62         if 'gp' not in func.info:
  63             sec = project.loader.find_section_containing(func.addr)
  64             if sec is None or sec.name != '.plt':
  65                 # this might a special case: gp is only used once in this function, and it can be initialized right before
  66                 # its use site.
  67                 # TODO: handle this case
  68                 l.debug('Failed to determine value of register gp for function %#x.', func.addr)
  69                 return False, [ ]
  70         else:
  71             state.regs.gp = func.info['gp']
  72 
  73         def overwrite_tmp_value(state):
  74             state.inspect.tmp_write_expr = state.solver.BVV(func.info['gp'], state.arch.bits)
  75 
  76         # Special handling for cases where `gp` is stored on the stack
  77         got_gp_stack_store = False
  78         for block_addr_in_slice in set(slice_node[0] for slice_node in b.slice.nodes()):
  79             for stmt in project.factory.block(block_addr_in_slice).vex.statements:
  80                 if isinstance(stmt, pyvex.IRStmt.Put) and stmt.offset == gp_offset and \
  81                         isinstance(stmt.data, pyvex.IRExpr.RdTmp):
  82                     tmp_offset = stmt.data.tmp  # pylint:disable=cell-var-from-loop
  83                     # we must make sure value of that temporary variable equals to the correct gp value
  84                     state.inspect.make_breakpoint('tmp_write', when=BP_BEFORE,
  85                                                   condition=lambda s, bbl_addr_=block_addr_in_slice,
  86                                                                    tmp_offset_=tmp_offset:
  87                                                   s.scratch.bbl_addr == bbl_addr_ and s.inspect.tmp_write_num == tmp_offset_,
  88                                                   action=overwrite_tmp_value
  89                                                   )
  90                     got_gp_stack_store = True
  91                     break
  92             if got_gp_stack_store:
  93                 break
  94 
  95         simgr = self.project.factory.simulation_manager(state)
  96         simgr.use_technique(Slicecutor(annotated_cfg))
  97         simgr.run()
  98 
  99         if simgr.cut:
  100             target = simgr.cut[0].addr
  101 
  102             if self._is_target_valid(cfg, target):
  103                 l.debug("Indirect jump at %#x is resolved to target %#x.", addr, target)
  104                 return True, [ target ]
  105 
  106             l.debug("Indirect jump at %#x is resolved to target %#x, which seems to be invalid.", addr, target)
  107             return False, [ ]
  108 
  109         l.debug("Indirect jump at %#x cannot be resolved by %s.", addr, repr(self))
  110         return False, [ ]
  111
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py b/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py
  --- a/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py
  +++ b/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py
  @@ -97,7 +97,13 @@
           simgr.run()
   
           if simgr.cut:
  -            target = simgr.cut[0].addr
  +            # pick the successor that is cut right after executing `addr`
  +            try:
  +                target_state = next(iter(cut for cut in simgr.cut if cut.history.addr == addr))
  +            except StopIteration:
  +                l.debug("Indirect jump at %#x cannot be resolved by %s.", addr, repr(self))
  +                return False, [ ]
  +            target = target_state.addr
   
               if self._is_target_valid(cfg, target):
                   l.debug("Indirect jump at %#x is resolved to target %#x.", addr, target)
  
verification_info: {"golden_diff": "diff --git a/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py b/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py\n--- a/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py\n+++ b/angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py\n@@ -97,7 +97,13 @@\n         simgr.run()\n \n         if simgr.cut:\n-            target = simgr.cut[0].addr\n+            # pick the successor that is cut right after executing `addr`\n+            try:\n+                target_state = next(iter(cut for cut in simgr.cut if cut.history.addr == addr))\n+            except StopIteration:\n+                l.debug(\"Indirect jump at %#x cannot be resolved by %s.\", addr, repr(self))\n+                return False, [ ]\n+            target = target_state.addr\n \n             if self._is_target_valid(cfg, target):\n                 l.debug(\"Indirect jump at %#x is resolved to target %#x.\", addr, target)\n", "issue": "Strange successors of the return block of a function\nI'm analysing a MIPS binary when facing the problem.\r\n\r\nThe problem exists in the funcition `do_ssc`.\r\n\r\nIn the following block which has a return statement\r\n![image](https://user-images.githubusercontent.com/8875073/69912053-4fb60900-145f-11ea-9152-4026aab7f033.png)\r\n\r\nWhen I run `node.successors` I got\r\n```\r\nIn [103]: end.successors                                                                                              \r\nOut[103]: \r\n[<CFGNode 0x40a7a8[28]>,\r\n <CFGNode do_ssc+0x12c [28]>,\r\n <CFGNode do_ssc+0x4c4 [28]>,\r\n <CFGNode do_ssc+0x45c [24]>,\r\n <CFGNode do_ssc+0x2a8 [24]>]\r\n```\r\nTheir addresses are `0x40a7a8`, `0x40a33c`, `0x40a6d4` and `0x40a4b8` respectively.\r\n\r\nI know the cfg of angr is interfunctional, however, only `0x40a7a8` is an caller of `do_ssc`.\r\n\r\nMay I know why other threes exist?\r\n\r\n\r\n\n", "before_files": [{"content": "\nimport logging\n\nimport pyvex\nimport archinfo\n\n\nfrom .... import options, BP_BEFORE\nfrom ....blade import Blade\nfrom ....annocfg import AnnotatedCFG\nfrom ....exploration_techniques import Slicecutor\n\nfrom .resolver import IndirectJumpResolver\n\n\nl = logging.getLogger(name=__name__)\n\n\nclass MipsElfFastResolver(IndirectJumpResolver):\n    def __init__(self, project):\n        super(MipsElfFastResolver, self).__init__(project, timeless=True)\n\n    def filter(self, cfg, addr, func_addr, block, jumpkind):\n        if not isinstance(self.project.arch, (archinfo.ArchMIPS32, archinfo.ArchMIPS64, )):\n            return False\n        return True\n\n    def resolve(self, cfg, addr, func_addr, block, jumpkind):\n        \"\"\"\n        Resolves the indirect jump in MIPS ELF binaries where all external function calls are indexed using gp.\n\n        :param cfg: A CFG instance.\n        :param int addr: IRSB address.\n        :param int func_addr: The function address.\n        :param pyvex.IRSB block: The IRSB.\n        :param str jumpkind: The jumpkind.\n        :return: If it was resolved and targets alongside it\n        :rtype: tuple\n        \"\"\"\n\n        project = self.project\n\n        b = Blade(cfg.graph, addr, -1, cfg=cfg, project=project, ignore_sp=True, ignore_bp=True,\n                  ignored_regs=('gp',)\n                  )\n\n        sources = [n for n in b.slice.nodes() if b.slice.in_degree(n) == 0]\n        if not sources:\n            return False, []\n\n        source = sources[0]\n        source_addr = source[0]\n        annotated_cfg = AnnotatedCFG(project, None, detect_loops=False)\n        annotated_cfg.from_digraph(b.slice)\n\n        state = project.factory.blank_state(addr=source_addr, mode=\"fastpath\",\n                                            remove_options=options.refs\n                                            )\n        func = cfg.kb.functions.function(addr=func_addr)\n\n        gp_offset = project.arch.registers['gp'][0]\n        if 'gp' not in func.info:\n            sec = project.loader.find_section_containing(func.addr)\n            if sec is None or sec.name != '.plt':\n                # this might a special case: gp is only used once in this function, and it can be initialized right before\n                # its use site.\n                # TODO: handle this case\n                l.debug('Failed to determine value of register gp for function %#x.', func.addr)\n                return False, [ ]\n        else:\n            state.regs.gp = func.info['gp']\n\n        def overwrite_tmp_value(state):\n            state.inspect.tmp_write_expr = state.solver.BVV(func.info['gp'], state.arch.bits)\n\n        # Special handling for cases where `gp` is stored on the stack\n        got_gp_stack_store = False\n        for block_addr_in_slice in set(slice_node[0] for slice_node in b.slice.nodes()):\n            for stmt in project.factory.block(block_addr_in_slice).vex.statements:\n                if isinstance(stmt, pyvex.IRStmt.Put) and stmt.offset == gp_offset and \\\n                        isinstance(stmt.data, pyvex.IRExpr.RdTmp):\n                    tmp_offset = stmt.data.tmp  # pylint:disable=cell-var-from-loop\n                    # we must make sure value of that temporary variable equals to the correct gp value\n                    state.inspect.make_breakpoint('tmp_write', when=BP_BEFORE,\n                                                  condition=lambda s, bbl_addr_=block_addr_in_slice,\n                                                                   tmp_offset_=tmp_offset:\n                                                  s.scratch.bbl_addr == bbl_addr_ and s.inspect.tmp_write_num == tmp_offset_,\n                                                  action=overwrite_tmp_value\n                                                  )\n                    got_gp_stack_store = True\n                    break\n            if got_gp_stack_store:\n                break\n\n        simgr = self.project.factory.simulation_manager(state)\n        simgr.use_technique(Slicecutor(annotated_cfg))\n        simgr.run()\n\n        if simgr.cut:\n            target = simgr.cut[0].addr\n\n            if self._is_target_valid(cfg, target):\n                l.debug(\"Indirect jump at %#x is resolved to target %#x.\", addr, target)\n                return True, [ target ]\n\n            l.debug(\"Indirect jump at %#x is resolved to target %#x, which seems to be invalid.\", addr, target)\n            return False, [ ]\n\n        l.debug(\"Indirect jump at %#x cannot be resolved by %s.\", addr, repr(self))\n        return False, [ ]\n", "path": "angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py"}], "after_files": [{"content": "\nimport logging\n\nimport pyvex\nimport archinfo\n\n\nfrom .... import options, BP_BEFORE\nfrom ....blade import Blade\nfrom ....annocfg import AnnotatedCFG\nfrom ....exploration_techniques import Slicecutor\n\nfrom .resolver import IndirectJumpResolver\n\n\nl = logging.getLogger(name=__name__)\n\n\nclass MipsElfFastResolver(IndirectJumpResolver):\n    def __init__(self, project):\n        super(MipsElfFastResolver, self).__init__(project, timeless=True)\n\n    def filter(self, cfg, addr, func_addr, block, jumpkind):\n        if not isinstance(self.project.arch, (archinfo.ArchMIPS32, archinfo.ArchMIPS64, )):\n            return False\n        return True\n\n    def resolve(self, cfg, addr, func_addr, block, jumpkind):\n        \"\"\"\n        Resolves the indirect jump in MIPS ELF binaries where all external function calls are indexed using gp.\n\n        :param cfg: A CFG instance.\n        :param int addr: IRSB address.\n        :param int func_addr: The function address.\n        :param pyvex.IRSB block: The IRSB.\n        :param str jumpkind: The jumpkind.\n        :return: If it was resolved and targets alongside it\n        :rtype: tuple\n        \"\"\"\n\n        project = self.project\n\n        b = Blade(cfg.graph, addr, -1, cfg=cfg, project=project, ignore_sp=True, ignore_bp=True,\n                  ignored_regs=('gp',)\n                  )\n\n        sources = [n for n in b.slice.nodes() if b.slice.in_degree(n) == 0]\n        if not sources:\n            return False, []\n\n        source = sources[0]\n        source_addr = source[0]\n        annotated_cfg = AnnotatedCFG(project, None, detect_loops=False)\n        annotated_cfg.from_digraph(b.slice)\n\n        state = project.factory.blank_state(addr=source_addr, mode=\"fastpath\",\n                                            remove_options=options.refs\n                                            )\n        func = cfg.kb.functions.function(addr=func_addr)\n\n        gp_offset = project.arch.registers['gp'][0]\n        if 'gp' not in func.info:\n            sec = project.loader.find_section_containing(func.addr)\n            if sec is None or sec.name != '.plt':\n                # this might a special case: gp is only used once in this function, and it can be initialized right before\n                # its use site.\n                # TODO: handle this case\n                l.debug('Failed to determine value of register gp for function %#x.', func.addr)\n                return False, [ ]\n        else:\n            state.regs.gp = func.info['gp']\n\n        def overwrite_tmp_value(state):\n            state.inspect.tmp_write_expr = state.solver.BVV(func.info['gp'], state.arch.bits)\n\n        # Special handling for cases where `gp` is stored on the stack\n        got_gp_stack_store = False\n        for block_addr_in_slice in set(slice_node[0] for slice_node in b.slice.nodes()):\n            for stmt in project.factory.block(block_addr_in_slice).vex.statements:\n                if isinstance(stmt, pyvex.IRStmt.Put) and stmt.offset == gp_offset and \\\n                        isinstance(stmt.data, pyvex.IRExpr.RdTmp):\n                    tmp_offset = stmt.data.tmp  # pylint:disable=cell-var-from-loop\n                    # we must make sure value of that temporary variable equals to the correct gp value\n                    state.inspect.make_breakpoint('tmp_write', when=BP_BEFORE,\n                                                  condition=lambda s, bbl_addr_=block_addr_in_slice,\n                                                                   tmp_offset_=tmp_offset:\n                                                  s.scratch.bbl_addr == bbl_addr_ and s.inspect.tmp_write_num == tmp_offset_,\n                                                  action=overwrite_tmp_value\n                                                  )\n                    got_gp_stack_store = True\n                    break\n            if got_gp_stack_store:\n                break\n\n        simgr = self.project.factory.simulation_manager(state)\n        simgr.use_technique(Slicecutor(annotated_cfg))\n        simgr.run()\n\n        if simgr.cut:\n            # pick the successor that is cut right after executing `addr`\n            try:\n                target_state = next(iter(cut for cut in simgr.cut if cut.history.addr == addr))\n            except StopIteration:\n                l.debug(\"Indirect jump at %#x cannot be resolved by %s.\", addr, repr(self))\n                return False, [ ]\n            target = target_state.addr\n\n            if self._is_target_valid(cfg, target):\n                l.debug(\"Indirect jump at %#x is resolved to target %#x.\", addr, target)\n                return True, [ target ]\n\n            l.debug(\"Indirect jump at %#x is resolved to target %#x, which seems to be invalid.\", addr, target)\n            return False, [ ]\n\n        l.debug(\"Indirect jump at %#x cannot be resolved by %s.\", addr, repr(self))\n        return False, [ ]\n", "path": "angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py"}]}