Repository: angr/angr

Issue:
Result of massive experiment: exception AssertionError during CFG creation
From the CFG and decompilation experiment across architectures on Debian. Results attached, which have the packages and binaries and exceptions in question.

Attached is a 7zip renamed as a PNG because github doesn't accept xz. Warning: might expand to many gigabytes.
![CFG_FAIL-AssertionError xz](https://user-images.githubusercontent.com/3453847/68734785-ce263600-0598-11ea-84a8-1b626ca55cd3.png)

SHAME



Discussion:
Binaries from multiple architectures are affected (amd64, armhf, mips64el). 237 instances of this one assertion.

```
################################################################################
### EVENT: CFG_FAIL
### Package: http://cdn-fastly.deb.debian.org/debian/pool/main/b/ben/ben_0.7.4+b4_amd64.deb
### Binary: ./usr/bin/ben
### Function: NONE - NONE
### Exception:
Traceback (most recent call last):
File "./process.py", line 21, in catcher
yield
File "./process.py", line 59, in doit_raw
cfg = elf.analyses.CFG(data_references=True, cross_references=True)
File "/home/angr/angr-dev/angr/angr/analyses/analysis.py", line 109, in __call__
oself.__init__(*args, **kwargs)
File "/home/angr/angr-dev/angr/angr/analyses/cfg/cfg.py", line 55, in __init__
CFGFast.__init__(self, **kwargs)
File "/home/angr/angr-dev/angr/angr/analyses/cfg/cfg_fast.py", line 643, in __init__
self._analyze()
File "/home/angr/angr-dev/angr/angr/analyses/forward_analysis/__init__.py", line 218, in _analyze
self._analysis_core_baremetal()
File "/home/angr/angr-dev/angr/angr/analyses/forward_analysis/__init__.py", line 346, in _analysis_core_baremetal
self._job_queue_empty()
File "/home/angr/angr-dev/angr/angr/analyses/cfg/cfg_fast.py", line 1123, in _job_queue_empty
self._process_unresolved_indirect_jumps()
File "/home/angr/angr-dev/angr/angr/analyses/cfg/cfg_base.py", line 2185, in _process_unresolved_indirect_jumps
all_targets |= self._process_one_indirect_jump(jump)
File "/home/angr/angr-dev/angr/angr/analyses/cfg/cfg_base.py", line 2211, in _process_one_indirect_jump
resolved, targets = resolver.resolve(self, jump.addr, jump.func_addr, block, jump.jumpkind)
File "/home/angr/angr-dev/angr/angr/analyses/cfg/indirect_jump_resolvers/jumptable.py", line 456, in resolve
r, targets = self._resolve(cfg, addr, func_addr, b)
File "/home/angr/angr-dev/angr/angr/analyses/cfg/indirect_jump_resolvers/jumptable.py", line 574, in _resolve
stmts_adding_base_addr, all_addr_holders)
File "/home/angr/angr-dev/angr/angr/analyses/cfg/indirect_jump_resolvers/jumptable.py", line 956, in _try_resolve_targets
assert len(stmts_adding_base_addr) == 1  # Making sure we are only dealing with one operation here
AssertionError
```
That is a stupid check for catching cases that I did not think of when I developed the algorithm. I'll briefly look into this after lunch.
Any news on this? I'm running into the same error.

Resolving patch:
diff --git a/angr/analyses/cfg/indirect_jump_resolvers/jumptable.py b/angr/analyses/cfg/indirect_jump_resolvers/jumptable.py
--- a/angr/analyses/cfg/indirect_jump_resolvers/jumptable.py
+++ b/angr/analyses/cfg/indirect_jump_resolvers/jumptable.py
@@ -1081,7 +1081,23 @@ def _try_resolve_targets_load(self, r, addr, cfg, annotatedcfg, load_stmt, load_
 
         # sanity check and necessary pre-processing
         if stmts_adding_base_addr:
-            assert len(stmts_adding_base_addr) == 1  # Making sure we are only dealing with one operation here
+            if len(stmts_adding_base_addr) != 1:
+                # We do not support the cases where the base address involves more than one addition.
+                # One such case exists in libc-2.27.so shipped with Ubuntu x86 where esi is used as the address of the
+                # data region.
+                #
+                # .text:00047316 mov     eax, esi
+                # .text:00047318 mov     esi, [ebp+data_region_ptr]
+                # .text:0004731E movsx   eax, al
+                # .text:00047321 movzx   eax, byte ptr [esi+eax-603A0h]
+                # .text:00047329 mov     eax, ds:(jpt_47337 - 1D8000h)[esi+eax*4] ; switch 32 cases
+                # .text:00047330 lea     eax, (loc_47033 - 1D8000h)[esi+eax] ; jumptable 00047337 cases 0-13,27-31
+                # .text:00047337 jmp     eax             ; switch
+                #
+                # the proper solution requires angr to correctly determine that esi is the beginning address of the data
+                # region (in this case, 0x1d8000). we give up in such cases until we can reasonably perform a
+                # full-function data propagation before performing jump table recovery.
+                return None
             jump_base_addr = stmts_adding_base_addr[0]
             if jump_base_addr.base_addr_available:
                 addr_holders = {(jump_base_addr.stmt_loc[0], jump_base_addr.tmp)}


Test patch: