Repository: angr/angr

Issue:
CFGFast throws a SimSolverModeError while building the CFG of this ARM library
The exception:

```
----> 1 cfg = p.analyses.CFGFast()

/home/edg/code/angr-dev/angr/angr/analyses/analysis.pyc in __call__(self, *args, **kwargs)
    106 
    107         oself._show_progressbar = show_progressbar
--> 108         oself.__init__(*args, **kwargs)
    109         return oself
    110 

/home/edg/code/angr-dev/angr/angr/analyses/cfg/cfg_fast.pyc in __init__(self, binary, regions, pickle_intermediate_results, symbols, function_prologues, resolve_indirect_jumps, force_segment, force_complete_scan, indirect_jump_target_limit, collect_data_references, extra_cross_references, normalize, start_at_entry, function_starts, extra_memory_regions, data_type_guessing_handlers, arch_options, indirect_jump_resolvers, base_state, exclude_sparse_regions, skip_specific_regions, heuristic_plt_resolving, start, end, **extra_arch_options)
    905 
    906         # Start working!
--> 907         self._analyze()
    908 
    909     #

/home/edg/code/angr-dev/angr/angr/analyses/forward_analysis.pyc in _analyze(self)
    557             self._analysis_core_graph()
    558 
--> 559         self._post_analysis()
    560 
    561     def _analysis_core_graph(self):

/home/edg/code/angr-dev/angr/angr/analyses/cfg/cfg_fast.pyc in _post_analysis(self)
   1462             self.normalize()
   1463 
-> 1464         self.make_functions()
   1465         # optional: remove functions that must be alignments
   1466         self.remove_function_alignments()

/home/edg/code/angr-dev/angr/angr/analyses/cfg/cfg_base.pyc in make_functions(self)
   1351         removed_functions = self._process_irrational_functions(tmp_functions,
   1352                                                                set([n.addr for n in function_nodes]),
-> 1353                                                                blockaddr_to_function
   1354                                                                )
   1355 

/home/edg/code/angr-dev/angr/angr/analyses/cfg/cfg_base.pyc in _process_irrational_functions(self, functions, predetermined_function_addrs, blockaddr_to_function)
   1528                     # using successors is slow, but acceptable since we won't be creating millions of blocks here...
   1529                     tmp_state.ip = last_addr
-> 1530                     b = self.project.factory.successors(tmp_state, jumpkind='Ijk_Boring')
   1531                     if len(b.successors) != 1:
   1532                         break

/home/edg/code/angr-dev/angr/angr/factory.pyc in successors(self, *args, **kwargs)
     59         """
     60 
---> 61         return self.project.engines.successors(*args, **kwargs)
     62 
     63     def blank_state(self, **kwargs):

/home/edg/code/angr-dev/angr/angr/engines/hub.pyc in successors(self, state, addr, jumpkind, default_engine, procedure_engine, engines, **kwargs)
    126         for engine in engines:
    127             if engine.check(state, **kwargs):
--> 128                 r = engine.process(state, **kwargs)
    129                 if r.processed:
    130                     return r

/home/edg/code/angr-dev/angr/angr/engines/vex/engine.pyc in process(self, state, irsb, skip_stmts, last_stmt, whitelist, inline, force_addr, insn_bytes, size, num_inst, traceflags, thumb, opt_level, **kwargs)
    133                 traceflags=traceflags,
    134                 thumb=thumb,
--> 135                 opt_level=opt_level)
    136 
    137     def _check(self, state, *args, **kwargs):

/home/edg/code/angr-dev/angr/angr/engines/engine.pyc in process(***failed resolving arguments***)
     53         successors = new_state._inspect_getattr('sim_successors', successors)
     54         try:
---> 55             self._process(new_state, successors, *args, **kwargs)
     56         except SimException:
     57             if o.EXCEPTION_HANDLING not in old_state.options:

/home/edg/code/angr-dev/angr/angr/engines/vex/engine.pyc in _process(self, state, successors, irsb, skip_stmts, last_stmt, whitelist, insn_bytes, size, num_inst, traceflags, thumb, opt_level)
    157                     traceflags=traceflags,
    158                     thumb=thumb,
--> 159                     opt_level=opt_level)
    160 
    161             if irsb.size == 0:

/home/edg/code/angr-dev/angr/angr/engines/vex/engine.pyc in lift(self, state, clemory, insn_bytes, arch, addr, size, num_inst, traceflags, thumb, opt_level, strict_block_end)
    502             buff, size = insn_bytes, len(insn_bytes)
    503         else:
--> 504             buff, size = self._load_bytes(addr, size, state, clemory)
    505 
    506         if not buff or size == 0:

/home/edg/code/angr-dev/angr/angr/engines/vex/engine.pyc in _load_bytes(self, addr, max_size, state, clemory)
    574         if size == 0 and state:
    575             if addr in state.memory and addr + max_size - 1 in state.memory:
--> 576                 buff = state.se.eval(state.memory.load(addr, max_size, inspect=False), cast_to=str)
    577                 size = max_size
    578             else:

/home/edg/code/angr-dev/angr/angr/state_plugins/solver.pyc in eval(self, e, **kwargs)
    704         """
    705         # eval_upto already throws the UnsatError, no reason for us to worry about it
--> 706         return self.eval_upto(e, 1, **kwargs)[0]
    707 
    708     def eval_one(self, e, **kwargs):

/home/edg/code/angr-dev/angr/angr/state_plugins/solver.pyc in eval_upto(self, e, n, cast_to, **kwargs)
    687             return [self._cast_to(e, concrete_val, cast_to)]
    688 
--> 689         cast_vals = [self._cast_to(e, v, cast_to) for v in self._eval(e, n, **kwargs)]
    690         if len(cast_vals) == 0:
    691             raise SimUnsatError('Not satisfiable: %s, expected up to %d solutions' % (e.shallow_repr(), n))

/home/edg/code/angr-dev/angr/angr/state_plugins/solver.pyc in concrete_shortcut_tuple(self, *args, **kwargs)
    153         v = _concrete_value(args[0])
    154         if v is None:
--> 155             return f(self, *args, **kwargs)
    156         else:
    157             return ( v, )

/home/edg/code/angr-dev/angr/angr/state_plugins/sim_action_object.pyc in ast_stripper(*args, **kwargs)
     51         new_args = _raw_ast(args)
     52         new_kwargs = _raw_ast(kwargs)
---> 53         return f(*new_args, **new_kwargs)
     54     return ast_stripper
     55 

/home/edg/code/angr-dev/angr/angr/state_plugins/solver.pyc in wrapped_f(*args, **kwargs)
     84     def wrapped_f(*args, **kwargs):
     85         try:
---> 86             return f(*args, **kwargs)
     87         except claripy.UnsatError:
     88             e_type, value, traceback = sys.exc_info()

/home/edg/code/angr-dev/angr/angr/state_plugins/solver.pyc in _eval(self, e, n, extra_constraints, exact)
    479         :rtype: tuple
    480         """
--> 481         return self._solver.eval(e, n, extra_constraints=self._adjust_constraint_list(extra_constraints), exact=exact)
    482 
    483     @concrete_path_scalar

/home/edg/code/angr-dev/claripy/claripy/frontend_mixins/concrete_handler_mixin.pyc in eval(self, e, n, **kwargs)
      5             return (c,)
      6         else:
----> 7             return super(ConcreteHandlerMixin, self).eval(e, n, **kwargs)
      8 
      9     def batch_eval(self, exprs, n, **kwargs): #pylint:disable=unused-argument

/home/edg/code/angr-dev/claripy/claripy/frontend_mixins/constraint_filter_mixin.pyc in eval(self, e, n, extra_constraints, **kwargs)
     38     def eval(self, e, n, extra_constraints=(), **kwargs):
     39         ec = self._constraint_filter(extra_constraints)
---> 40         return super(ConstraintFilterMixin, self).eval(e, n, extra_constraints=ec, **kwargs)
     41 
     42     def batch_eval(self, exprs, n, extra_constraints=(), **kwargs):

/home/edg/code/angr-dev/claripy/claripy/frontends/light_frontend.pyc in eval(self, e, n, extra_constraints, exact)
     40             return tuple(self._solver_backend.eval(e, n))
     41         except BackendError:
---> 42             raise ClaripyFrontendError("Light solver can't handle this eval().")
     43 
     44     def batch_eval(self, exprs, n, extra_constraints=(), exact=None):

SimSolverModeError: ('Translated claripy error:', <class 'claripy.errors.ClaripyFrontendError'>, ClaripyFrontendError("Light solver can't handle this eval().",))
```

My environment:
```
angr environment report
=============================
Date: 2018-06-19 11:19:51.517506
Running in virtual environment at /home/edg/.virtualenvs/angr-dev
Platform: linux-x86_64
Python version: 2.7.12 (default, Dec  4 2017, 14:50:18) 
[GCC 5.4.0 20160609]
######## angr #########
Python found it in /home/edg/code/angr-dev/angr/angr
Pip version angr 7.8.6.16
Git info:
	Current commit f8304c4b1f0097a721a6692b02a45cabaae137c5 from branch master
	Checked out from remote origin: git@github.com:angr/angr
######## ailment #########
Python found it in /home/edg/.virtualenvs/angr-dev/local/lib/python2.7/site-packages/ailment
Pip version ailment 7.8.6.16
Couldn't find git info
######## cle #########
Python found it in /home/edg/code/angr-dev/cle/cle
Pip version cle 7.8.6.16
Git info:
	Current commit 03a275beff8fdf039f8889f5831639d9007b792c from branch master
	Checked out from remote origin: git@github.com:angr/cle
######## pyvex #########
Python found it in /home/edg/.virtualenvs/angr-dev/local/lib/python2.7/site-packages/pyvex
Pip version pyvex 7.8.6.16
Couldn't find git info
######## claripy #########
Python found it in /home/edg/code/angr-dev/claripy/claripy
Pip version claripy 7.8.6.16
Git info:
	Current commit b5cfa0a355eaa3cd5403e1d81f0b80bb3db20c90 from branch master
	Checked out from remote origin: git@github.com:angr/claripy
######## archinfo #########
Python found it in /home/edg/.virtualenvs/angr-dev/local/lib/python2.7/site-packages/archinfo
Pip version archinfo 7.8.6.16
Couldn't find git info
######## ana #########
Python found it in /home/edg/code/angr-dev/ana/ana
Pip version ana 0.5
Git info:
	Current commit 48657dc6500e33f5818b98003f1f179bfe03e1cc from branch master
	Checked out from remote origin: https://git:@github.com/zardus/ana
######## simuvex #########
Python found it in /home/edg/code/angr-dev/simuvex/simuvex
Pip version simuvex 7.7.9.8
Git info:
	Current commit b03fb87b5c2809be4240bc3243321ee802ea3dd2 from branch master
	Checked out from remote origin: git@git.seclab.cs.ucsb.edu:angr/simuvex
######## z3 #########
Python found it in /home/edg/.virtualenvs/angr-dev/local/lib/python2.7/site-packages/z3
Pip version not found!
Couldn't find git info
######## unicorn #########
Python found it in /home/edg/.virtualenvs/angr-dev/local/lib/python2.7/site-packages/unicorn
Pip version unicorn 1.0.1
Couldn't find git info
######### Native Module Info ##########
pyvex: <cffi.api.FFILibrary_/home/edg/.virtualenvs/angr-dev/local/lib/python2.7/site-packages/pyvex/lib/libpyvex.so object at 0x7f6cb8ce6d10>
z3: <CDLL '/home/edg/.virtualenvs/angr-dev/lib/python2.7/site-packages/z3/lib/libz3.so', handle 24c8da0 at 7f6cb4099f90>
angr: <CDLL '/home/edg/code/angr-dev/angr/angr/lib/angr_native.so', handle 1cc60e0 at 7f6cb62b8e50>
unicorn: <CDLL '/home/edg/.virtualenvs/angr-dev/local/lib/python2.7/site-packages/unicorn/lib/libunicorn.so', handle 182d410 at 7f6cb815d190>
```

What I did:
```
import angr

p = angr.Project("I2C.o")

cfg = p.analyses.CFGFast()

```

The binary (attached) is a Cortex-M library, but there shouldn't be any messy stuff, it's just a high-level library wrapper thingy.


[I2C.zip](https://github.com/angr/angr/files/2116425/I2C.zip)



Discussion:

Resolving patch:
diff --git a/angr/engines/vex/engine.py b/angr/engines/vex/engine.py
--- a/angr/engines/vex/engine.py
+++ b/angr/engines/vex/engine.py
@@ -572,18 +572,27 @@ def _load_bytes(self, addr, max_size, state=None, clemory=None):
 
         # If that didn't work, try to load from the state
         if size == 0 and state:
+            fallback = True
             if addr in state.memory and addr + max_size - 1 in state.memory:
-                buff = state.se.eval(state.memory.load(addr, max_size, inspect=False), cast_to=str)
-                size = max_size
-            else:
-                good_addrs = []
+                try:
+                    buff = state.se.eval(state.memory.load(addr, max_size, inspect=False), cast_to=str)
+                    size = max_size
+                    fallback = False
+                except SimError:
+                    l.warning("Cannot load bytes at %#x. Fallback to the slow path.", addr)
+
+            if fallback:
+                buff_lst = [ ]
                 for i in xrange(max_size):
                     if addr + i in state.memory:
-                        good_addrs.append(addr + i)
+                        try:
+                            buff_lst.append(chr(state.se.eval(state.memory.load(addr + i, 1, inspect=False))))
+                        except SimError:
+                            break
                     else:
                         break
 
-                buff = ''.join(chr(state.se.eval(state.memory.load(i, 1, inspect=False))) for i in good_addrs)
+                buff = ''.join(buff_lst)
                 size = len(buff)
 
         size = min(max_size, size)


Test patch: