Skip to content

[Fix][Relax][VM] Keep the call_py_func registry alive until process exit - #20413

Open
LiRunGuo wants to merge 1 commit into
apache:mainfrom
LiRunGuo:fix/relax-py-func-registry
Open

LiRunGuo wants to merge 1 commit into
apache:mainfrom
LiRunGuo:fix/relax-py-func-registry

Conversation

@LiRunGuo

@LiRunGuo LiRunGuo commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

The Python function registry used by R.call_py_func is a static std::unordered_map. Its destructor runs during static destruction, after the Python interpreter has been finalized, and releases the Python callables it still holds. Any process that exits with a function still registered therefore crashes:

import tvm
tvm.get_global_func("vm.builtin.register_py_func")("f", lambda x: x)
# process exits with SIGSEGV (exit code 139)

This makes the registry a heap-allocated singleton that is never destroyed, so nothing is released after finalization. The new test runs the snippet above in a subprocess and checks that it exits with code 0; it fails on current main and passes with this change. tests/python/relax/test_relax_operators.py and the relax test suite otherwise pass.

Note: the first version of this PR also fixed the flaky test_op_call_py_func failure caused by BasePyModule.__del__ clearing the whole registry. #20417 has since fixed that with per-module ownership, so I rebased onto main and reduced this PR to the exit crash, which #20417 does not address.

@LiRunGuo

Copy link
Copy Markdown
Contributor Author

Hi @tlopex @MasterJH5574, could you help review this when you have time? It fixes the flaky test_op_call_py_func failure seen in CI (e.g. #20406) and a crash at process exit when a Python function is still registered. Thanks!

@LiRunGuo
LiRunGuo force-pushed the fix/relax-py-func-registry branch from bf215fb to 301df76 Compare October 12, 2026 20:53
@LiRunGuo LiRunGuo changed the title [Fix][Relax][VM] Stop BasePyModule from wiping the call_py_func registry [Fix][Relax][VM] Keep the call_py_func registry alive until process exit Oct 12, 2026
@LiRunGuo

Copy link
Copy Markdown
Contributor Author

Since #20417 already fixed the flaky test by scoping registry entries to their module, I rebased and reduced this PR to the remaining exit crash (process segfaults if a Python function is still registered at exit). @tlopex @MasterJH5574 could you take a look? Thanks!

The Python function registry used by `R.call_py_func` was a static
std::unordered_map. Its destructor runs during static destruction, after
the Python interpreter has been finalized, and releases the Python
callables it still holds. Any process that exits with a function still
registered therefore crashes:

  import tvm
  tvm.get_global_func("vm.builtin.register_py_func")("f", lambda x: x)
  # exits with SIGSEGV

Make the registry a heap-allocated singleton that is never destroyed, so
nothing is released after finalization, and add a test that a process
exiting with a function still registered returns 0.
@LiRunGuo
LiRunGuo force-pushed the fix/relax-py-func-registry branch from 301df76 to cf4fb50 Compare November 3, 2026 16:41
@LiRunGuo

LiRunGuo commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (cbb1e12fe0); no semantic changes were needed. Head cf4fb50f34; static checks pass. GitHub Actions is running.

This branch has not been deployed

No deployments
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

Successfully merging this pull request may close these issues.

1 participant