palkeo / panoramix

Ethereum decompiler
MIT License
812 stars 215 forks source link

Panoramix fails to work not in main thread (and does not work in Windows) #10

Open NikZak opened 3 years ago

NikZak commented 3 years ago

ERROR:panoramix.decompiler:Problem with name() Traceback (most recent call last): File "/opt/homebrew/lib/python3.9/site-packages/panoramix/decompiler.py", line 177, in _decompile_with_loader trace = dec() File "/opt/homebrew/lib/python3.9/site-packages/timeout_decorator/timeout_decorator.py", line 75, in new_function old = signal.signal(signal.SIGALRM, handler) File "/opt/homebrew/Cellar/python@3.9/3.9.5/Frameworks/Python.framework/Versions/3.9/lib/python3.9/signal.py", line 47, in signal handler = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler)) ValueError: signal only works in main thread of the main interpreter

This happens because panoramix in one place uses timeout-decorator library. Precisely here in panoramix/decompiler.py

def _decompile_with_loader(loader, only_func_name=None) -> Decompilation:
    ...
      @timeout_decorator.timeout(60 * 3, timeout_exception=TimeoutInterrupt)
      def dec():
        trace = VM(loader).run(target, stack=stack, timeout=60)

timeout_decorator project actually describes this problem here:

_Multithreading By default, timeout-decorator uses signals to limit the execution time of the given function. This appoach does not work if your function is executed not in a main thread (for example if it’s a worker thread of the web application). There is alternative timeout strategy for this case - by using multiprocessing. To use it, just pass usesignals=False to the timeout decorator function:

But just adding use_signals=False would not work as the object is sophisticated enough and can not be pickled which is required by the multiprocessing module

So the full solution to this problem is: 1) pip install wrapt_timeout_decorator

2) add to panoramix/decompiler.py

from wrapt_timeout_decorator import timeout

3) replace

def _decompile_with_loader(loader, only_func_name=None) -> Decompilation:
    ...
      @timeout_decorator.timeout(60 * 3, timeout_exception=TimeoutInterrupt)
      def dec():
        trace = VM(loader).run(target, stack=stack, timeout=60)

with

def _decompile_with_loader(loader, only_func_name=None) -> Decompilation:
    ...
      @timeout(60 * 3, timeout_exception=TimeoutInterrupt, use_signals=False)
      def dec():
        trace = VM(loader).run(target, stack=stack, timeout=60)

This solves the failure to work not in main thread problem and should also solve not working in Windows problem (although I can not test the second statement)

I can submit a pull request, just let me know

FuzzyDev2021 commented 3 years ago

Can confirm that editing the code as suggested above fixes it on my Windows machine.

papunku commented 2 years ago

Nice project