Implement user variadic model interface (#276)
* Add variadic decorator * Add check for _variadic func attribute * Expose @variadic at top level * Use variable for the actual name of attr * Update naming * Use helper * Maybe more pythonic? * Add variadic to public API * Add variadic decorator tests * Clean * Remove variadic parameter * Add docstrings * Document parameter * Clean * Better use of autodoc * Update docstring * Add todo comment
This commit is contained in:
@@ -7,7 +7,8 @@ This API is under active development, and should be considered unstable.
|
||||
Helpers
|
||||
-------
|
||||
|
||||
.. autofunction:: manticore.issymbolic
|
||||
.. automodule:: manticore
|
||||
:members: issymbolic, variadic
|
||||
|
||||
Manticore
|
||||
---------
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
from .manticore import Manticore
|
||||
from .models import variadic
|
||||
from .utils.helpers import issymbolic
|
||||
|
||||
@@ -220,16 +220,16 @@ class Abi(object):
|
||||
yield base
|
||||
base += word_bytes
|
||||
|
||||
def invoke(self, model, prefix_args=None, varargs=False):
|
||||
def invoke(self, model, prefix_args=None):
|
||||
'''
|
||||
Invoke a callable `model` as if it was a native function. If `varargs`
|
||||
is true, model receives a single argument that is a generator for
|
||||
function arguments. Pass a tuple of arguments for `prefix_args` you'd
|
||||
like to precede the actual arguments.
|
||||
Invoke a callable `model` as if it was a native function. If
|
||||
:func:`~manticore.models.isvariadic` returns true for `model`, `model` receives a single
|
||||
argument that is a generator for function arguments. Pass a tuple of
|
||||
arguments for `prefix_args` you'd like to precede the actual
|
||||
arguments.
|
||||
|
||||
:param callable model: Python model of the function
|
||||
:param tuple prefix_args: Parameters to pass to model before actual ones
|
||||
:param bool varargs: Whether the function expects a variable number of arguments
|
||||
:return: The result of calling `model`
|
||||
'''
|
||||
prefix_args = prefix_args or ()
|
||||
@@ -255,8 +255,11 @@ class Abi(object):
|
||||
descriptors = self.get_arguments()
|
||||
argument_iter = imap(resolve_argument, descriptors)
|
||||
|
||||
# TODO(mark) this is here as a hack to avoid circular import issues
|
||||
from ...models import isvariadic
|
||||
|
||||
try:
|
||||
if varargs:
|
||||
if isvariadic(model):
|
||||
result = model(*(prefix_args + (argument_iter,)))
|
||||
else:
|
||||
argument_tuple = prefix_args + tuple(islice(argument_iter, nargs))
|
||||
@@ -265,7 +268,7 @@ class Abi(object):
|
||||
assert e.argnum >= len(prefix_args), "Can't concretize a constant arg"
|
||||
idx = e.argnum - len(prefix_args)
|
||||
|
||||
# Arguments were lazily computed in case of varargs, so recompute here
|
||||
# Arguments were lazily computed in case of variadic, so recompute here
|
||||
descriptors = self.get_arguments()
|
||||
src = next(islice(descriptors, idx, idx+1))
|
||||
|
||||
|
||||
@@ -243,10 +243,11 @@ class State(object):
|
||||
def invoke_model(self, model):
|
||||
'''
|
||||
Invoke a `model`. A `model` is a callable whose first argument is a
|
||||
:class:`~manticore.core.state.State`, and whose following arguments correspond to
|
||||
the C function being modeled.
|
||||
:class:`~manticore.core.state.State`. If the `model` models a normal (non-variadic)
|
||||
function, the following arguments correspond to the arguments of the C function
|
||||
being modeled. If the `model` models a variadic function, the following argument
|
||||
is a generator object, which can be used to access function arguments dynamically.
|
||||
|
||||
:param callable model: Model to invoke
|
||||
'''
|
||||
# TODO(mark): this can't support varargs core models!
|
||||
self.platform.invoke_model(model, prefix_args=(self,))
|
||||
|
||||
@@ -3,6 +3,26 @@ from .utils.helpers import issymbolic
|
||||
from .core.smtlib.solver import solver
|
||||
from .core.smtlib.operators import ITEBV, ZEXTEND
|
||||
|
||||
VARIADIC_FUNC_ATTR = '_variadic'
|
||||
|
||||
def isvariadic(model):
|
||||
"""
|
||||
:param callable model: Function model
|
||||
:return: Whether `model` models a variadic function
|
||||
:rtype: bool
|
||||
"""
|
||||
return getattr(model, VARIADIC_FUNC_ATTR, False)
|
||||
|
||||
def variadic(func):
|
||||
"""
|
||||
A decorator used to mark a function model as variadic. This function should
|
||||
take two parameters: a :class:`~manticore.core.state.State` object, and
|
||||
a generator object for the arguments.
|
||||
|
||||
:param callable func: Function model
|
||||
"""
|
||||
setattr(func, VARIADIC_FUNC_ATTR, True)
|
||||
return func
|
||||
|
||||
def _find_zero(cpu, constrs, ptr):
|
||||
"""
|
||||
|
||||
@@ -9,5 +9,5 @@ class Platform(object):
|
||||
def __init__(self, path):
|
||||
self._path = path
|
||||
|
||||
def invoke_model(self, model, prefix_args=None, varargs=False):
|
||||
self._function_abi.invoke(model, prefix_args, varargs)
|
||||
def invoke_model(self, model, prefix_args=None):
|
||||
self._function_abi.invoke(model, prefix_args)
|
||||
|
||||
@@ -12,6 +12,7 @@ import collections
|
||||
import time
|
||||
|
||||
from manticore import Manticore, issymbolic
|
||||
from manticore import variadic
|
||||
from manticore.core.smtlib import BitVecVariable
|
||||
from manticore.core.cpu.abstractcpu import ConcretizeArgument, ConcretizeRegister, ConcretizeMemory
|
||||
from manticore.core.cpu.arm import Armv7Cpu, Armv7LinuxSyscallAbi, Armv7CdeclAbi
|
||||
@@ -250,11 +251,12 @@ class ABITests(unittest.TestCase):
|
||||
# save return
|
||||
cpu.push(0x1234, cpu.address_bit_size)
|
||||
|
||||
@variadic
|
||||
def test(params):
|
||||
for val, idx in zip(params, range(1, 4)):
|
||||
self.assertEqual(val, idx)
|
||||
|
||||
cpu.func_abi.invoke(test, varargs=True)
|
||||
cpu.func_abi.invoke(test)
|
||||
self.assertEquals(cpu.EIP, 0x1234)
|
||||
|
||||
|
||||
@@ -333,11 +335,12 @@ class ABITests(unittest.TestCase):
|
||||
# save return
|
||||
cpu.push(0x1234, cpu.address_bit_size)
|
||||
|
||||
@variadic
|
||||
def test(params):
|
||||
for val, idx in zip(params, range(3)):
|
||||
self.assertEqual(val, idx)
|
||||
|
||||
cpu.func_abi.invoke(test, varargs=True)
|
||||
cpu.func_abi.invoke(test)
|
||||
|
||||
self.assertEquals(cpu.RIP, 0x1234)
|
||||
|
||||
|
||||
@@ -4,7 +4,19 @@ from manticore.core.smtlib import ConstraintSet, solver
|
||||
from manticore.core.state import State
|
||||
from manticore.platforms import linux
|
||||
|
||||
from manticore.models import strcmp, strlen
|
||||
from manticore.models import variadic, isvariadic, strcmp, strlen
|
||||
|
||||
class ModelMiscTest(unittest.TestCase):
|
||||
def test_variadic_dec(self):
|
||||
@variadic
|
||||
def f():
|
||||
pass
|
||||
self.assertTrue(isvariadic(f))
|
||||
|
||||
def test_no_variadic_dec(self):
|
||||
def f():
|
||||
pass
|
||||
self.assertFalse(isvariadic(f))
|
||||
|
||||
|
||||
class ModelTest(unittest.TestCase):
|
||||
|
||||
Reference in New Issue
Block a user