Commit f9e10bb
Fix QuickJS NAPI weak-reference and ExternalCallback self-cycle leaks
Two correctness bugs in the QuickJS NAPI implementation caused objects
to be pinned forever, contributing to the assert(list_empty(&rt->gc_obj_list))
failure in JS_FreeRuntime at teardown:
1. napi_create_reference always called JS_DupValue regardless of the
initial refcount. Per Node-API semantics a reference created with
count=0 is a *weak* reference that must not keep its value alive.
The dup silently promoted it to strong, which meant every
ObjectWrap<T> instance (which uses napi_wrap -> napi_create_reference
with count=0 as a weak self-ref) was pinned forever, its
FinalizeCallback never fired, and its C++ destructor never ran.
Fixed by only dupping when count > 0, and paired the matching
delete/ref/unref paths so:
- napi_delete_reference only frees the dup when count > 0
- napi_reference_ref on 0->1 takes a dup (weak -> strong)
- napi_reference_unref on 1->0 frees the dup (strong -> weak)
2. ExternalCallback::newTarget was stored as JS_DupValue(func) which
created a self-cycle: func -> c_function_data -> opaque
ExternalCallback -> newTarget -> func. Because NapiCallback class has
gc_mark=nullptr the cycle collector cannot break this. Store the raw
JSValue instead; it is only read during callback invocation when
QuickJS itself holds func alive.
Measured impact on UnitTests on Android arm64 (debug):
- Leaked GC objects at teardown: 11147 -> 10751 (-396)
- Leaked ObjectWrap instances: 151 -> 52 (-99)
- Leaked NapiWrap prototypes: 151 -> 52 (-99)
- 136 tests still pass (no regressions)
The assert still fires (remaining leaks are dominated by bytecode
closures transitively pinned via persistent polyfill singletons), but
these two bugs are genuine leaks independent of the rest.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>1 parent fe26c61 commit f9e10bb
1 file changed
Lines changed: 45 additions & 11 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
176 | 176 | | |
177 | 177 | | |
178 | 178 | | |
179 | | - | |
| 179 | + | |
| 180 | + | |
180 | 181 | | |
181 | 182 | | |
182 | 183 | | |
| |||
942 | 943 | | |
943 | 944 | | |
944 | 945 | | |
945 | | - | |
| 946 | + | |
| 947 | + | |
| 948 | + | |
| 949 | + | |
| 950 | + | |
| 951 | + | |
| 952 | + | |
| 953 | + | |
946 | 954 | | |
947 | 955 | | |
948 | 956 | | |
| |||
1682 | 1690 | | |
1683 | 1691 | | |
1684 | 1692 | | |
1685 | | - | |
1686 | | - | |
| 1693 | + | |
| 1694 | + | |
| 1695 | + | |
| 1696 | + | |
| 1697 | + | |
| 1698 | + | |
| 1699 | + | |
| 1700 | + | |
| 1701 | + | |
1687 | 1702 | | |
1688 | 1703 | | |
1689 | 1704 | | |
| |||
1694 | 1709 | | |
1695 | 1710 | | |
1696 | 1711 | | |
1697 | | - | |
| 1712 | + | |
| 1713 | + | |
| 1714 | + | |
| 1715 | + | |
| 1716 | + | |
| 1717 | + | |
1698 | 1718 | | |
1699 | 1719 | | |
1700 | 1720 | | |
| |||
1704 | 1724 | | |
1705 | 1725 | | |
1706 | 1726 | | |
1707 | | - | |
| 1727 | + | |
1708 | 1728 | | |
| 1729 | + | |
| 1730 | + | |
| 1731 | + | |
| 1732 | + | |
| 1733 | + | |
| 1734 | + | |
1709 | 1735 | | |
1710 | | - | |
| 1736 | + | |
1711 | 1737 | | |
1712 | 1738 | | |
1713 | 1739 | | |
1714 | | - | |
| 1740 | + | |
1715 | 1741 | | |
1716 | 1742 | | |
1717 | 1743 | | |
1718 | 1744 | | |
1719 | 1745 | | |
1720 | 1746 | | |
1721 | 1747 | | |
1722 | | - | |
| 1748 | + | |
1723 | 1749 | | |
1724 | 1750 | | |
1725 | 1751 | | |
| 1752 | + | |
| 1753 | + | |
| 1754 | + | |
| 1755 | + | |
| 1756 | + | |
| 1757 | + | |
| 1758 | + | |
| 1759 | + | |
1726 | 1760 | | |
1727 | | - | |
| 1761 | + | |
1728 | 1762 | | |
1729 | 1763 | | |
1730 | 1764 | | |
1731 | | - | |
| 1765 | + | |
1732 | 1766 | | |
1733 | 1767 | | |
1734 | 1768 | | |
| |||
0 commit comments