Repository: angr/angr

Issue:
CFGEmulated crashes for some binaries
<!--
*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.
-->
When executed on some binaries, CFGEmulated crashes with a TypeError:
`TypeError: FunctionDict only supports <class 'int'> as key type`

**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.
-->
Date: 2019-10-28 09:30:23.326609
Running in virtual environment at /home/user/.virtualenvs/angrNew
Platform: linux-x86_64
Python version: 3.5.3 (928a4f70d3de, Feb 08 2019, 10:42:58)
[PyPy 7.0.0 with GCC 6.2.0 20160901]
######## angr #########
Python found it in /home/user/Documents/Thesis/angr/angr-dev/angr/angr
Pip version angr 8.19.7.25
Git info:
	Current commit 378664acef860eee11cab6be6023d35d413c88be from branch master
	Checked out from remote origin: https://github.com/angr/angr
######## ailment #########
Python found it in /home/user/Documents/Thesis/angr/angr-dev/ailment/ailment
Pip version ailment 8.19.7.25
Git info:
	Current commit b8bacaa65480cffb8056fd44d2fa4627ea1832b3 from branch master
	Checked out from remote origin: https://github.com/angr/ailment
######## cle #########
Python found it in /home/user/Documents/Thesis/angr/angr-dev/cle/cle
Pip version cle 8.19.7.25
Git info:
	Current commit d5e0329aa8c150b52933680e52f40099ba6b5236 from branch master
	Checked out from remote origin: https://github.com/angr/cle
######## pyvex #########
Python found it in /home/user/Documents/Thesis/angr/angr-dev/pyvex/pyvex
Pip version pyvex 8.19.7.25
Git info:
	Current commit d67020a7fe15c8171955cf68f6f5f539654989f5 from branch master
	Checked out from remote origin: https://github.com/angr/pyvex
######## claripy #########
Python found it in /home/user/Documents/Thesis/angr/angr-dev/claripy/claripy
Pip version claripy 8.19.7.25
Git info:
	Current commit f7a56fdcf139a6d9c4710d245a0c425caeddf0be from branch master
	Checked out from remote origin: https://github.com/angr/claripy
######## archinfo #########
Python found it in /home/user/Documents/Thesis/angr/angr-dev/archinfo/archinfo
Pip version archinfo 8.19.7.25
Git info:
	Current commit 81818c8aa9c8e8c7455255a3fcc69924598f8e50 from branch master
	Checked out from remote origin: https://github.com/angr/archinfo
######## z3 #########
Python found it in /home/user/.virtualenvs/angrNew/site-packages/z3
Pip version z3-solver 4.8.6.0
Couldn't find git info
######## unicorn #########
Python found it in /home/user/.virtualenvs/angrNew/site-packages/unicorn
Pip version unicorn 1.0.1
Couldn't find git info
######### Native Module Info ##########
angr: <CDLL '/home/user/Documents/Thesis/angr/angr-dev/angr/angr/lib/angr_native.so', handle 48853b0 at 0x7f3a8ad59a60>
unicorn: <CDLL '/home/user/.virtualenvs/angrNew/site-packages/unicorn/lib/libunicorn.so', handle 300b5d0 at 0x7f3a9048af00>
pyvex: <cffi.api._make_ffi_library.<locals>.FFILibrary object at 0x00007f3a9161d478>
z3: <CDLL '/home/user/.virtualenvs/angrNew/site-packages/z3/lib/libz3.so', handle 27b3e70 at 0x7f3a8e965de0>

**To Reproduce.**
<!--
Please include *both a script to reproduce the crash, and attach the binary used, if possible*
-->
Download and extract the angrBug zip file(Which contains a short python script and problematic binary) into a directory. Use cd to navigate to the directory. Then, execute:
`python3 CFGEmulatedbug.py make-prime-list`
Within a minute, CFGEmulated should crash.
[angrBug.zip](https://github.com/angr/angr/files/3777773/angrBug.zip)

**Additional context.**
<!--
Add any other context about the problem here.
-->
Here is the output when the bug occurs:
[angrBug.txt](https://github.com/angr/angr/files/3777792/angrBug.txt)




Discussion:
Has anyone been able to reproduce the bug on their machine?

Resolving patch:
diff --git a/angr/analyses/cfg/cfg_emulated.py b/angr/analyses/cfg/cfg_emulated.py
--- a/angr/analyses/cfg/cfg_emulated.py
+++ b/angr/analyses/cfg/cfg_emulated.py
@@ -1984,10 +1984,13 @@ def _update_function_transition_graph(self, src_node_key, dst_node_key, jumpkind
         """
         Update transition graphs of functions in function manager based on information passed in.
 
-        :param str jumpkind: Jumpkind.
-        :param CFGNode src_node: Source CFGNode
-        :param CFGNode dst_node: Destionation CFGNode
-        :param int ret_addr: The theoretical return address for calls
+        :param src_node_key:    Node key of the source CFGNode. Might be None.
+        :param dst_node:        Node key of the destination CFGNode. Might be None.
+        :param str jumpkind:    Jump kind of this transition.
+        :param int ret_addr:    The theoretical return address for calls.
+        :param int or None ins_addr:    Address of the instruction where this transition is made.
+        :param int or None stmt_idx:    ID of the statement where this transition is made.
+        :param bool or None confirmed:  Whether this call transition has been confirmed or not.
         :return: None
         """
 
diff --git a/angr/knowledge_plugins/functions/function_manager.py b/angr/knowledge_plugins/functions/function_manager.py
--- a/angr/knowledge_plugins/functions/function_manager.py
+++ b/angr/knowledge_plugins/functions/function_manager.py
@@ -110,22 +110,36 @@ def _add_node(self, function_addr, node, syscall=None, size=None):
 
     def _add_call_to(self, function_addr, from_node, to_addr, retn_node=None, syscall=None, stmt_idx=None, ins_addr=None,
                      return_to_outside=False):
+        """
+        Add a call to a function.
+
+        :param int function_addr:   Address of the current function where this call happens.
+        :param from_node:           The source node.
+        :param to_addr:             Address of the target function, or None if unknown.
+        :param retn_node:           The node where the target function will return to if it returns.
+        :param bool syscall:        If this is a call to a syscall or not.
+        :param int stmt_idx:        ID of the statement where this call happens.
+        :param int ins_addr:        Address of the instruction where this call happens.
+        :param bool return_to_outside:  True if the return of the call is considered going to outside of the current
+                                        function.
+        :return:                    None
+        """
 
         if isinstance(from_node, self.address_types):
             from_node = self._kb._project.factory.snippet(from_node)
         if isinstance(retn_node, self.address_types):
             retn_node = self._kb._project.factory.snippet(retn_node)
-        dest_func = self._function_map[to_addr]
-        if syscall in (True, False):
-            dest_func.is_syscall = syscall
-
         func = self._function_map[function_addr]
-
-        func._call_to(from_node, dest_func, retn_node, stmt_idx=stmt_idx, ins_addr=ins_addr,
-                      return_to_outside=return_to_outside
-                      )
         func._add_call_site(from_node.addr, to_addr, retn_node.addr if retn_node else None)
 
+        if to_addr is not None:
+            dest_func = self._function_map[to_addr]
+            if syscall in (True, False):
+                dest_func.is_syscall = syscall
+            func._call_to(from_node, dest_func, retn_node, stmt_idx=stmt_idx, ins_addr=ins_addr,
+                          return_to_outside=return_to_outside
+                          )
+
         if return_to_outside:
             func.add_retout_site(from_node)
 


Test patch: