Skip to content

webassembly: Fix GC tracing of object returned from top-level functions.#19141

Open
dpgeorge wants to merge 1 commit into
micropython:masterfrom
dpgeorge:webassembly-fix-premature-gc-collection
Open

webassembly: Fix GC tracing of object returned from top-level functions.#19141
dpgeorge wants to merge 1 commit into
micropython:masterfrom
dpgeorge:webassembly-fix-premature-gc-collection

Conversation

@dpgeorge
Copy link
Copy Markdown
Member

Summary

This commit makes sure that the GC explicitly traces the Python object returned from all top-level functions. Without this, it's possible that a JsProxy that is created as the return object is freed on the Python side (and hence the underlying JavaScript object entry set to undefined) just prior to the top-level C function returning. So when it does return and control resumes on the JavaScript side, the JavaScript object corresponding to the JsProxy is gone.

For example, the case covered by the test added here has the return value (Python object) from proxy_c_to_js_call() reclaimed by the Python GC via proxy_js_free_obj() before it can be accessed from the JavaScript side, and so the JavaScript reference in proxy_js_ref is undefined,

Testing

I found this in a web app I'm building, there was some strange behaviour which was traced to the issue fixed here. That web app now behaves correctly with this fix.

Also added a test which triggers the same problem. It'll run in CI.

Trade-offs and Alternatives

There may be other ways to structure the fix, but PR #18021 already fixed a related case, and this PR is extending/improving upon that fix.

Generative AI

I did not use generative AI tools when creating this PR.

This commit makes sure that the GC explicitly traces the Python object
returned from all top-level functions.  Without this, it's possible that a
JsProxy that is created as the return object is freed on the Python side
(and hence the underlying JavaScript object entry set to `undefined`) just
prior to the top-level C function returning.  So when it does return and
control resumes on the JavaScript side, the JavaScript object corresponding
to the JsProxy is gone.

For example, the case covered by the test added here has the return value
(Python object) from `proxy_c_to_js_call()` reclaimed by the Python GC via
`proxy_js_free_obj()` before it can be accessed from the JavaScript side,
and so the JavaScript reference in `proxy_js_ref` is `undefined`,

Signed-off-by: Damien George <damien@micropython.org>
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 23, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.46%. Comparing base (8a56be6) to head (1926bc8).

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #19141   +/-   ##
=======================================
  Coverage   98.46%   98.46%           
=======================================
  Files         176      176           
  Lines       22811    22811           
=======================================
  Hits        22460    22460           
  Misses        351      351           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant