Repository: angr/angr

Issue:
`ReturnDuplicator` incorrectly duplicating tail jumps
### Description

I was trying to decompile all the functions in the binary, and decompiling "function" at 0x2070 gives following exception:

```python
Traceback (most recent call last):
  File "/home/[redacted]/ailment/tagged_object.py", line 29, in __getattr__
    return self.tags[item]
KeyError: 'ret_exprs'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/han/scratch/binbenchfeb7/_angr.py", line 17, in <module>
    p.analyses.Decompiler(func, cfg=cfg)
  File "/home/[redacted]/angr/analyses/analysis.py", line 216, in __call__
    r = w(*args, **kwargs)
  File "/home/[redacted]/angr/analyses/analysis.py", line 201, in wrapper
    oself.__init__(*args, **kwargs)
  File "/home/[redacted]/angr/analyses/decompiler/decompiler.py", line 97, in __init__
    self._decompile()
  File "/home/[redacted]/angr/analyses/decompiler/decompiler.py", line 206, in _decompile
    clinic.graph, ri = self._run_region_simplification_passes(
  File "/home/[redacted]/angr/utils/timing.py", line 43, in timed_func
    return func(*args, **kwargs)
  File "/home/[redacted]/angr/analyses/decompiler/decompiler.py", line 356, in _run_region_simplification_passes
    a = pass_(
  File "/home/[redacted]/angr/analyses/decompiler/optimization_passes/return_duplicator.py", line 70, in __init__
    self.analyze()
  File "/home/[redacted]/angr/analyses/decompiler/optimization_passes/optimization_pass.py", line 290, in analyze
    self._fixed_point_analyze(cache=cache)
  File "/home/[redacted]/angr/analyses/decompiler/optimization_passes/optimization_pass.py", line 325, in _fixed_point_analyze
    changes = self._analyze(cache=cache)
  File "/home/[redacted]/angr/analyses/decompiler/optimization_passes/return_duplicator.py", line 86, in _analyze
    endnode_regions = self._copy_connected_edge_components(endnode_regions, self.out_graph)
  File "/home/[redacted]/angr/analyses/decompiler/optimization_passes/return_duplicator.py", line 246, in _copy_connected_edge_components
    is_single_const_ret_region = self._is_simple_return_graph(region)
  File "/home/[redacted]/angr/analyses/decompiler/optimization_passes/return_duplicator.py", line 339, in _is_simple_return_graph
    ret_exprs = ret_stmt.ret_exprs
  File "/home/[redacted]/ailment/tagged_object.py", line 31, in __getattr__
    return super().__getattribute__(item)
AttributeError: 'Jump' object has no attribute 'ret_exprs'
```

after checking the disasm, 0x2070 doesn't seems like a function start

```asm
.text:00002070 loc_2070:                               ; CODE XREF: quotearg_buffer_restyled+46E↑j
.text:00002070                                         ; DATA XREF: .rodata:jpt_206E↓o
.text:00002070                 test    [ebp+backslash_escapes], 1 ; jumptable 0000206E case 0
.text:00002074                 jz      loc_218D
.text:0000207A                 test    [ebp+elide_outer_quotes], 1
.text:0000207E                 jz      loc_2089
.text:00002084                 jmp     force_outer_quoting_style
```

### Steps to reproduce the bug

```python
import angr

p = angr.Project("hello_O0.o", load_options={"auto_load_libs": False, 'main_opts': {'base_addr': 0x0}})
cfg = p.analyses.CFGFast(data_references=True, normalize=True)
p.analyses[angr.analyses.CompleteCallingConventionsAnalysis].prep()(recover_variables=True)

for func in p.kb.functions.values():
    print(f"Function {hex(func.addr)}: {func.name}")

func = p.kb.functions[0x2070]
p.analyses.Decompiler(func, cfg=cfg)
```

### Environment

```bash
$ python3 -m angr.misc.bug_report
angr environment report
=============================
Date: 2024-02-08 17:23:05.970696
Running in virtual environment at /home/[redacted]/angr
/home/[redacted]/angr/lib/python3.10/site-packages/angr/misc/bug_report.py:88: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
  import pkg_resources  # pylint:disable=import-outside-toplevel
Platform: linux-x86_64
Python version: 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0]
######## angr #########
Python found it in /home/[redacted]/angr/lib/python3.10/site-packages/angr/__init__.py
Pip version angr 9.2.89
Couldn't find git info
######## ailment #########
Python found it in /home/[redacted]/angr/lib/python3.10/site-packages/ailment/__init__.py
Pip version ailment 9.2.89
Couldn't find git info
######## cle #########
Python found it in /home/[redacted]/angr/lib/python3.10/site-packages/cle/__init__.py
Pip version cle 9.2.89
Couldn't find git info
######## pyvex #########
Python found it in /home/[redacted]/angr/lib/python3.10/site-packages/pyvex/__init__.py
Pip version pyvex 9.2.89
Couldn't find git info
######## claripy #########
Python found it in /home/[redacted]/angr/lib/python3.10/site-packages/claripy/__init__.py
Pip version claripy 9.2.89
Couldn't find git info
######## archinfo #########
Python found it in /home/[redacted]/angr/lib/python3.10/site-packages/archinfo/__init__.py
Pip version archinfo 9.2.89
Couldn't find git info
######## z3 #########
Python found it in /home/[redacted]/angr/lib/python3.10/site-packages/z3/__init__.py
Pip version z3-solver 4.10.2.0
Couldn't find git info
######## unicorn #########
Python found it in /home/[redacted]/angr/lib/python3.10/site-packages/unicorn/__init__.py
Pip version unicorn 2.0.1.post1
Couldn't find git info
######### Native Module Info ##########
angr: <CDLL '/home/[redacted]/angr/lib/python3.10/site-packages/angr/state_plugins/../lib/angr_native.so', handle 562fd072a940 at 0x7f8cbbf29f90>
unicorn: <CDLL '/home/[redacted]/angr/lib/python3.10/site-packages/unicorn/lib/libunicorn.so.2', handle 562fd0190540 at 0x7f8cbf067f70>
pyvex: <cffi.api._make_ffi_library.<locals>.FFILibrary object at 0x7f8cbfde6920>
z3: <CDLL '/home/[redacted]/angr/lib/python3.10/site-packages/z3/lib/libz3.so', handle 562fcfe2f0b0 at 0x7f8cc1cf7be0>
```


### Additional context

Binary:
[hello_O0.zip](https://github.com/angr/angr/files/14215898/hello_O0.zip)


Discussion:
@DennyDai, do you know for certain if that place should be a function or not? It looks like I just messed up some checks on duplication for functions ending in a jmp as an exit.
@mahaloz It shouldn't be a function. 0x2070 should be part of the function that starts at 0x1c00, which contains a jump table (for switch-case) that angr failed to resolve.
@DennyDai can you actually open another issue for the false positive function? Even without it being a false positive, it should not crash in the optimization loop. I'll use this issue to track that bug. 
@mahaloz sure, I've opened #4460 just now, thanks for looking into this!

Resolving patch:
diff --git a/angr/analyses/decompiler/optimization_passes/return_duplicator.py b/angr/analyses/decompiler/optimization_passes/return_duplicator.py
--- a/angr/analyses/decompiler/optimization_passes/return_duplicator.py
+++ b/angr/analyses/decompiler/optimization_passes/return_duplicator.py
@@ -336,6 +336,11 @@ def _is_simple_return_graph(graph: networkx.DiGraph, max_assigns=1):
 
         # gather return stmts
         ret_stmt = stmts[-1]
+        if not isinstance(ret_stmt, Return):
+            if isinstance(ret_stmt, Jump):
+                _l.warning("Found a jump at the end of a return graph, did function analysis fail?")
+            return False
+
         ret_exprs = ret_stmt.ret_exprs
         # must be 1 or none
         if ret_exprs and len(ret_exprs) > 1:


Test patch: