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

EmterpreterAsyncify -> Asyncify Port not working #9279

Closed
AjayP13 opened this issue Aug 21, 2019 · 1 comment
Closed

EmterpreterAsyncify -> Asyncify Port not working #9279

AjayP13 opened this issue Aug 21, 2019 · 1 comment

Comments

@AjayP13
Copy link
Contributor

AjayP13 commented Aug 21, 2019

Hi,

I'm working on a full-featured port of CPython to JavaScript using Emscripten (still a WIP): https://github.com/plasticityai/coldbrew

There's a feature that allows running Python code asynchronously along side JavaScript using the Emterpreter's Asyncify. It basically performs a emscripten_sleep(1) in the interpreter loop of CPython every 100 Python bytecode instructions. By sleeping for 1ms, it yields back to the browser to handle any queued up events, and then returns back to the Python interpreter running in the Emterpreter. This all worked fine with Emterpreter's Asyncify.

I saw the new Asyncify option released recently and ported the project to use that instead (since it is much faster, great feature!) but have been running into issues getting it to work. It in general works sometimes, but produces a random RuntimeError: memory access out of bounds error for some, but not all, Python code (using no Python C imports other than builtin modules). The exact same code works fine on the Emterpreter Async. Here's what a stack trace looks like:

PyEval_EvalFrameEx | @ | wasm-03484dee-1571:42096
  | PyEval_EvalFrameEx | @ | wasm-03484dee-1571:26543
  | _PyEval_EvalCodeWithName | @ | wasm-03484dee-509:2889
  | PyRun_StringFlags | @ | wasm-03484dee-495:259
  | export_runAsync | @ | wasm-03484dee-499:362
  | ret.<computed> | @ | coldbrew.asm.js:10645
  | (anonymous) | @ | coldbrew.asm.js:10708
  | (anonymous) | @ | coldbrew.asm.js:8425
  | setTimeout (async) |   |  
  | setTimeout | @ | coldbrew.asm.js:289
  | safeSetTimeout | @ | coldbrew.asm.js:8422
  | (anonymous) | @ | coldbrew.asm.js:8742
  | handleSleep | @ | coldbrew.asm.js:10693
  | _emscripten_sleep | @ | coldbrew.asm.js:8741
  | PyEval_EvalFrameEx | @ | wasm-03484dee-1571:838
  | _PyEval_EvalCodeWithName | @ | wasm-03484dee-509:2889
  | PyEval_EvalFrameEx | @ | wasm-03484dee-1571:26704
  | _PyEval_EvalCodeWithName | @ | wasm-03484dee-509:2889
  | PyEval_EvalFrameEx | @ | wasm-03484dee-1571:26704
  | PyEval_EvalFrameEx | @ | wasm-03484dee-1571:26543
  | _PyEval_EvalCodeWithName | @ | wasm-03484dee-509:2889
  | PyRun_StringFlags | @ | wasm-03484dee-495:259
  | export_runAsync | @ | wasm-03484dee-499:362
  | ret.<computed> | @ | coldbrew.asm.js:10645
  | Module._export_runAsync | @ | coldbrew.asm.js:11282
  | ccall | @ | coldbrew.asm.js:984
  | (anonymous) | @ | coldbrew.asm.js:994
  | Coldbrew.runAsync | @ | coldbrew.asm.js:13315
  | (anonymous) | @ | VM178:1

It looks like it resumes and restores the stack after the _emscripten_sleep, but then crashes a little bit later on in a seemingly random place due to corrupted memory?

Here are some notes on my configuration:

  1. Running in Chrome (but crash also happens in Firefox)
  2. I am using the upstream LLVM backend, but have this flag -s WASM_OBJECT_FILES=0 set to turn off WASM object files. Don't think this should affect anything?
  3. I'm calling the function using ccall. I know Asyncify doesn't support ccall Promises yet (ccall + ASYNCIFY promise support #9029), so I call it with the 'async' flag turned off (to prevent the assertion error).

Here's what I've learned from debugging attempts so far:

  1. Build with just -s ASYNCIFY=1 and let it do static analysis to figure out which functions to instrument. (Didn't work).
  2. Build with -s ASYNCIFY_WHITELIST=@async_funcs.tmp with all functions in the wasm binary using a dump of all function names from llvm-nm in case the static analyzer is missing some functions for some reason. (Doesn't work)
  3. I'm fairly confident this isn't some issue with CPython trying to use corrupted memory. The exact same Python code works if you remove the call to emscripten_sleep(1). It seems to explicitly have to do with unwinding and rewinding the stack and something happening in that process.

Any advice for further debugging would be greatly appreciated.

@AjayP13
Copy link
Contributor Author

AjayP13 commented Aug 21, 2019

Solved. It was ccall. It is actually not safe to use it with Asyncify at all, even if you don't care about the return value not being returned as a Promise, because the stackRestore() call corrupts the memory. It seems like it makes sense then to go ahead and fix Issue #9029.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant