Repository: angr/angr

Issue:
CFGFast fails on armel binaries:  "TypeError: expected string or bytes-like object"
<!--
*Disclaimer:
The angr suite is maintained by a small team of volunteers.
While we cannot guarantee any timeliness for fixes and enhancements, we will do our best.
For more real-time help with angr, from us and the community, join our [Slack.](http://angr.io/invite/)*
-->
---

**Describe the bug.**
<!--
Please include a clear and concise description of what the bug is.
-->
Hi, I'm trying to migrate the [karonte project](https://github.com/ucsb-seclab/karonte) to angr 8. But CFGFast fails on many binaries from the provided testcase.
This is the test scirpt I used:
```python
import angr
import sys

def test_cfg(path):
    p = angr.Project(path, auto_load_libs=False)
    cfg = p.analyses.CFGFast(show_progressbar=False)

if __name__ == "__main__":
    test_cfg(sys.argv[1])
```
` /firmware/NETGEAR/analyzed/R7800/firmware/squashfs-root/usr/sbin/uhttpd` and `/firmware/NETGEAR/analyzed/R7800/firmware/squashfs-root/usr/sbin/hostapd` from the karonte testset as examples:
```
Traceback (most recent call last):
  File "test.py", line 4, in <module>
    cfg = proj.analyses.CFGFast(show_progressbar=True)
  File "/home/angr_fork/angr/analyses/analysis.py", line 115, in __call__
    oself.__init__(*args, **kwargs)
  File "/home/angr_fork/angr/analyses/cfg/cfg_fast.py", line 653, in __init__
    self._analyze()
  File "/home/angr_fork/angr/analyses/forward_analysis/forward_analysis.py", line 216, in _analyze
    self._analysis_core_baremetal()
  File "/home/angr_fork/angr/analyses/forward_analysis/forward_analysis.py", line 344, in _analysis_core_baremetal
    self._job_queue_empty()
  File "/home/angr_fork/angr/analyses/cfg/cfg_fast.py", line 1192, in _job_queue_empty
    if any(re.match(prolog, bytes_prefix) for prolog in self.project.arch.thumb_prologs):
  File "/home/angr_fork/angr/analyses/cfg/cfg_fast.py", line 1192, in <genexpr>
    if any(re.match(prolog, bytes_prefix) for prolog in self.project.arch.thumb_prologs):
  File "/home/angr_fork/venv/lib/python3.6/re.py", line 172, in match
    return _compile(pattern, flags).match(string)
TypeError: expected string or bytes-like object
```

**Environment Information.**
<!--
Many common issues are caused by problems with the local Python environment.
Before submitting, double-check that your versions of all modules in the angr suite (angr, cle, pyvex, ...) are up to date.
Please include the output of `python -m angr.misc.bug_report` here.
-->
```
angr environment report
=============================
Date: 2020-06-17 17:13:14.650762
Running in virtual environment at /home/angr_fork/venv
Platform: linux-x86_64
Python version: 3.6.9 (default, Apr 18 2020, 01:56:04) 
[GCC 8.4.0]
######## angr #########
Python found it in angr
Pip version angr 8.20.6.8
Git info:
	Current commit c78830d8e7fdc82d45cfe3a002623eddfb58cc8d from branch fix_cfgfast_arm
Could not resolve tracking branch or remote info!
######## ailment #########
Python could not find ailment
######## cle #########
Python found it in /home/angr_fork/venv/lib/python3.6/site-packages/cle-8.20.6.8-py3.6.egg/cle
Pip version cle 8.20.6.8
Git info:
	Current commit c78830d8e7fdc82d45cfe3a002623eddfb58cc8d from branch fix_cfgfast_arm
Could not resolve tracking branch or remote info!
######## pyvex #########
Python found it in /home/angr_fork/.eggs/pyvex-8.20.6.8-py3.6-linux-x86_64.egg/pyvex
Pip version pyvex 8.20.6.8
Git info:
	Current commit c78830d8e7fdc82d45cfe3a002623eddfb58cc8d from branch fix_cfgfast_arm
Could not resolve tracking branch or remote info!
######## claripy #########
Python could not find claripy
######## archinfo #########
Python found it in /home/angr_fork/.eggs/archinfo-8.20.6.8-py3.6.egg/archinfo
Pip version archinfo 8.20.6.8
Git info:
	Current commit c78830d8e7fdc82d45cfe3a002623eddfb58cc8d from branch fix_cfgfast_arm
Could not resolve tracking branch or remote info!
######## z3 #########
Python found it in /home/angr_fork/venv/lib/python3.6/site-packages/z3_solver-4.8.8.0-py3.6-linux-x86_64.egg/z3
Pip version z3-solver 4.8.8.0
Git info:
	Current commit c78830d8e7fdc82d45cfe3a002623eddfb58cc8d from branch fix_cfgfast_arm
Could not resolve tracking branch or remote info!
######## unicorn #########
Python found it in /home/angr_fork/.eggs/unicorn-1.0.2rc4-py3.6-linux-x86_64.egg/unicorn
Pip version unicorn 1.0.2rc4
Git info:
	Current commit c78830d8e7fdc82d45cfe3a002623eddfb58cc8d from branch fix_cfgfast_arm
Could not resolve tracking branch or remote info!
######### Native Module Info ##########
angr: None
unicorn: <CDLL '/home/angr_fork/.eggs/unicorn-1.0.2rc4-py3.6-linux-x86_64.egg/unicorn/lib/libunicorn.so', handle 222ea70 at 0x7f66339e71d0>
pyvex: <cffi.api._make_ffi_library.<locals>.FFILibrary object at 0x7f66349c5c18>
z3: <CDLL '/home/angr_fork/venv/lib/python3.6/site-packages/z3_solver-4.8.8.0-py3.6-linux-x86_64.egg/z3/lib/libz3.so', handle 24ee6b0 at 0x7f6631677668>

```


**To Reproduce.**
<!--
Please include *both a script to reproduce the crash, and attach the binary used, if possible*
-->
This is tested in the latest docker image from https://hub.docker.com/r/angr/angr, and the failed binaries can be downloaded here:

[binaries.zip](https://github.com/angr/angr/files/4791466/binaries.zip)


**Additional context.**
<!--
Add any other context about the problem here.
-->



Discussion:
I saw your fix - that's an interesting fix. I wonder why we return None or empty after calling `self._fast_memory_load_bytes(addr, 8)`, since `addr` is returned by `_next_code_addr()` and it _must_ exists.
I don't know if I fix it in the correct way, it is a quick fix and avoid exception on some testcases. If you have a better fix and push it to the master branch, that helps a lot, thanks.

Resolving patch:
diff --git a/angr/analyses/cfg/cfg_fast.py b/angr/analyses/cfg/cfg_fast.py
--- a/angr/analyses/cfg/cfg_fast.py
+++ b/angr/analyses/cfg/cfg_fast.py
@@ -35,6 +35,10 @@
 l = logging.getLogger(name=__name__)
 
 
+class ContinueScanningNotification(RuntimeError):
+    pass
+
+
 class FunctionReturn:
     """
     FunctionReturn describes a function call in a specific location and its return location. Hashable and equatable
@@ -940,13 +944,20 @@ def _next_code_addr_core(self):
             self._seg_list.occupy(start_addr, instr_alignment - (start_addr % instr_alignment), 'alignment')
             start_addr = start_addr - start_addr % instr_alignment + \
                          instr_alignment
+            # trickiness: aligning the start_addr may create a new address that is outside any mapped region.
+            if not self._inside_regions(start_addr):
+                raise ContinueScanningNotification()
 
         return start_addr
 
     def _next_code_addr(self):
 
         while True:
-            addr = self._next_code_addr_core()
+            try:
+                addr = self._next_code_addr_core()
+            except ContinueScanningNotification:
+                continue
+
             if addr is None:
                 return None
 


Test patch: