Skip to content

Commit

Permalink
Fix inheritance magic and add plugin enable/disable (#1696)
Browse files Browse the repository at this point in the history
* Fix inheritance magic nonsens and add plugin enable/disable

* CC

* Better Plugin default

* Fix enabled default

* Trying to generalize enable/disable for plugins

* Merger is the only plugin using locked context correctly

* Fix plugin context name

* text to enum
  • Loading branch information
feliam authored May 13, 2020
1 parent 4f7027b commit 55e2486
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 91 deletions.
150 changes: 62 additions & 88 deletions manticore/core/manticore.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,65 @@ def to_class(self):


class ManticoreBase(Eventful):
def __new__(cls, *args, **kwargs):
if cls in (ManticoreBase, ManticoreSingle, ManticoreThreading, ManticoreMultiprocessing):
raise ManticoreError("Should not instantiate this")
def _manticore_single(self):
self._worker_type = WorkerSingle

cl = consts.mprocessing.to_class()
# change ManticoreBase for the more specific class
bases = {cl if issubclass(base, ManticoreBase) else base for base in cls.__bases__}
cls.__bases__ = tuple(bases)
class FakeLock:
def _nothing(self, *args, **kwargs):
pass

random.seed(consts.seed)
return super().__new__(cls)
acquire = _nothing
release = _nothing
__enter__ = _nothing
__exit__ = _nothing
notify_all = _nothing
wait = _nothing

def wait_for(self, condition, *args, **kwargs):
if not condition():
raise Exception("Deadlock: Waiting for CTRL+C")

self._lock = FakeLock()
self._killed = ctypes.c_bool(False)
self._running = ctypes.c_bool(False)
self._ready_states = []
self._terminated_states = []
self._busy_states = []
self._killed_states = []
self._shared_context = {}

def _manticore_threading(self):
self._worker_type = WorkerThread
self._lock = threading.Condition()
self._killed = ctypes.c_bool(False)
self._running = ctypes.c_bool(False)
self._ready_states = []
self._terminated_states = []
self._busy_states = []
self._killed_states = []
self._shared_context = {}

def _manticore_multiprocessing(self):
def raise_signal():
signal.signal(signal.SIGINT, signal.SIG_IGN)

self._worker_type = WorkerProcess
# This is the global manager that will handle all shared memory access
# See. https://docs.python.org/3/library/multiprocessing.html#multiprocessing.managers.SyncManager
self._manager = SyncManager()
self._manager.start(raise_signal)
# The main manticore lock. Acquire this for accessing shared objects
# THINKME: we use the same lock to access states lists and shared contexts
self._lock = self._manager.Condition()
self._killed = self._manager.Value(bool, False)
self._running = self._manager.Value(bool, False)
# List of state ids of States on storage
self._ready_states = self._manager.list()
self._terminated_states = self._manager.list()
self._busy_states = self._manager.list()
self._killed_states = self._manager.list()
self._shared_context = self._manager.dict()
self._context_value_types = {list: self._manager.list, dict: self._manager.dict}

# Decorators added first for convenience.
def sync(func: Callable) -> Callable: # type: ignore
Expand Down Expand Up @@ -255,6 +303,11 @@ def __init__(self, initial_state, workspace_url=None, outputspace_url=None, **kw
:param kwargs: other kwargs, e.g.
"""
super().__init__()
random.seed(consts.seed)
{consts.mprocessing.single: self._manticore_single,
consts.mprocessing.threading: self._manticore_threading,
consts.mprocessing.multiprocessing: self._manticore_multiprocessing
}[consts.mprocessing]()

if any(
not hasattr(self, x)
Expand Down Expand Up @@ -1008,82 +1061,3 @@ def save_run_data(self):
config.save(f)

logger.info("Results in %s", self._output.store.uri)


class ManticoreSingle(ManticoreBase):
_worker_type = WorkerSingle

def __init__(self, *args, **kwargs):
class FakeLock:
def _nothing(self, *args, **kwargs):
pass

acquire = _nothing
release = _nothing
__enter__ = _nothing
__exit__ = _nothing
notify_all = _nothing
wait = _nothing

def wait_for(self, condition, *args, **kwargs):
if not condition():
raise Exception("Deadlock: Waiting for CTRL+C")

self._lock = FakeLock()
self._killed = ctypes.c_bool(False)
self._running = ctypes.c_bool(False)

self._ready_states = []
self._terminated_states = []
self._busy_states = []
self._killed_states = []

self._shared_context = {}
super().__init__(*args, **kwargs)


class ManticoreThreading(ManticoreBase):
_worker_type = WorkerThread

def __init__(self, *args, **kwargs):
self._lock = threading.Condition()
self._killed = ctypes.c_bool(False)
self._running = ctypes.c_bool(False)

self._ready_states = []
self._terminated_states = []
self._busy_states = []
self._killed_states = []

self._shared_context = {}

super().__init__(*args, **kwargs)


def raise_signal():
signal.signal(signal.SIGINT, signal.SIG_IGN)


class ManticoreMultiprocessing(ManticoreBase):
_worker_type = WorkerProcess

def __init__(self, *args, **kwargs):
# This is the global manager that will handle all shared memory access
# See. https://docs.python.org/3/library/multiprocessing.html#multiprocessing.managers.SyncManager
self._manager = SyncManager()
self._manager.start(raise_signal)
# The main manticore lock. Acquire this for accessing shared objects
# THINKME: we use the same lock to access states lists and shared contexts
self._lock = self._manager.Condition()
self._killed = self._manager.Value(bool, False)
self._running = self._manager.Value(bool, False)

# List of state ids of States on storage
self._ready_states = self._manager.list()
self._terminated_states = self._manager.list()
self._busy_states = self._manager.list()
self._killed_states = self._manager.list()
self._shared_context = self._manager.dict()
self._context_value_types = {list: self._manager.list, dict: self._manager.dict}

super().__init__(*args, **kwargs)
40 changes: 38 additions & 2 deletions manticore/core/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,51 @@
import cProfile
import pstats
import threading
from functools import wraps

from .smtlib import issymbolic

logger = logging.getLogger(__name__)


class Plugin:

def __init__(self):
self.manticore = None
self._enabled_key = f"{str(type(self))}_enabled_{hash(self)}"
self._plugin_context_name = f"{str(type(self))}_context_{hash(self)}"
self.__decorate_callbacks()

def __decorate_callbacks(self):
for attr in self.__dict__:
if attr.endswith('_callback'):
method = getattr(self, attr)
if callable(method):
setattr(self, attr, self._if_enabled(method))

def enable(self):
""" Enable all callbacks """
with self.manticore.locked_context() as context:
context[self._enabled_key] = True

def disable(self):
""" Disable all callbacks """
with self.manticore.locked_context() as context:
context[self._enabled_key] = False

def is_enabled(self):
""" True if callbacks are enabled """
with self.manticore.locked_context() as context:
return context.get(self._enabled_key, True)

@staticmethod
def _if_enabled(f):
""" decorator used to guard callbacks """
@wraps(f)
def g(self, *args, **kwargs):
if self.is_enabled():
return f(self, *args, **kwargs)
return g

@property
def name(self):
Expand All @@ -25,7 +61,7 @@ def locked_context(self, key=None, value_type=list):
when parallel analysis is activated. Code within the `with` block is executed
atomically, so access of shared variables should occur within.
"""
plugin_context_name = str(type(self))
plugin_context_name = self._plugin_context_name
with self.manticore.locked_context(plugin_context_name, dict) as context:
if key is None:
yield context
Expand All @@ -37,7 +73,7 @@ def locked_context(self, key=None, value_type=list):
@property
def context(self):
""" Convenient access to shared context """
plugin_context_name = str(type(self))
plugin_context_name = self._plugin_context_name
if plugin_context_name not in self.manticore.context:
self.manticore.context[plugin_context_name] = {}
return self.manticore.context[plugin_context_name]
Expand Down
1 change: 0 additions & 1 deletion manticore/ethereum/plugins.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import sys

from functools import reduce

import re

from ..core.plugin import Plugin
Expand Down

0 comments on commit 55e2486

Please sign in to comment.