Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

python dynamic analysis: support async and generator function execution #968

Merged
merged 3 commits into from
Nov 16, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions sandboxes/dynamicanalysis/analyze-python.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
import asyncio
import importlib
import importlib.metadata
import inspect
Expand Down Expand Up @@ -197,11 +198,30 @@ def invoke_function(obj):
# any exceptions will be propagated to the caller
bound = signature.bind(*args, **kwargs)

# run with timeout to prevent hangs
# set timeout to prevent hangs
signal.alarm(EXECUTION_TIMEOUT_SECONDS)
ret = obj(*bound.args, **bound.kwargs)

# run function and await the result if necessary
# ret_obj is the object returned by the function, which may need
# further evaluation / awaiting to produce the return value
ret_obj = obj(*bound.args, **bound.kwargs)
if inspect.isasyncgen(ret_obj):
# async generator - await in a loop
async def execute():
return [x async for x in ret_obj]
ret_val = asyncio.run(execute())
elif inspect.isgenerator(ret_obj):
# normal generator - execute in a loop
ret_val = [x for x in ret_obj]
elif inspect.iscoroutine(ret_obj):
# async function - await run
ret_val = asyncio.run(ret_obj)
else:
# normal function - just run
ret_val = ret_obj

signal.alarm(0)
return ret
return ret_val


# Execute a callable and catch any exception, logging to stdout
Expand Down Expand Up @@ -238,7 +258,6 @@ def instantiate():
# tries to call the methods of the given object instance
# should_investigate and mark_seen are mutable input/output variables
# that track which types have been traversed
# TODO support calling async methods
def try_call_methods(instance, class_name, should_investigate, mark_seen):
print('[instance methods]', class_name)

Expand Down
Loading