Skip to content

fix(point): fix reference counting issues#466

Merged
ObserverOfTime merged 3 commits into
tree-sitter:masterfrom
haxtibal:bugfix/point_refcnt
Jul 8, 2026
Merged

fix(point): fix reference counting issues#466
ObserverOfTime merged 3 commits into
tree-sitter:masterfrom
haxtibal:bugfix/point_refcnt

Conversation

@haxtibal

@haxtibal haxtibal commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

See individual commit messages for details and reproducers.

The issues were spotted in StrictDoc CI when it started to pick up py-tree-sitter 0.26.0. See strictdoc-project/strictdoc#2986.

@haxtibal haxtibal changed the title WIP: Fix reference counting issues in Point(), causing resource leak and use after free Fix reference counting issues in Point(), causing resource leak and use after free Jul 2, 2026

@ObserverOfTime ObserverOfTime left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove the reproducers.

bdc2367 ('feat!: add edit method to point & range') turned Point
from a pure Python NamedTuple into a C extension tuple subtype with
PyGetSetDef getters for Point.row and Point.column.

According C-API getters must return a *new* reference [1], but a
borrowed reference was returned instead where refcount is 1 too low.
This can cause premature free and pymalloc free-list corruption,
eventually leading to SIGSEGV.

Fix point_get_row and point_get_column to return Py_NewRef instead of
the bare borrowed result.

[1] https://docs.python.org/3/c-api/structures.html#c.PyGetSetDef
@haxtibal haxtibal force-pushed the bugfix/point_refcnt branch from ceb845b to 6f31f0e Compare July 7, 2026 21:59
haxtibal added 2 commits July 8, 2026 00:04
point_new constructed the tuple with PyTuple_Pack(2, row_obj, col_obj),
which increments the refcount of each argument. The C locals row_obj
and col_obj were never Py_DECREF'd afterward, so the row/column PyLong
objects were held at refcount 2 instead of 1 and were never freed.

Fix by adding Py_XDECREF(row_obj) and Py_XDECREF(col_obj) after
PyTuple_Pack.

Fixes bdc2367 ('feat!: add edit method to point & range').
point_new allocated the tuple with PyTuple_Pack and then called
Py_SET_TYPE to change ob_type to the Point heap type. Py_SET_TYPE is a
bare pointer write that skips the bookkeeping PyObject_Init performs for
heap types, causing _PyObject_GenericGetAttrWithDict to crash on CPython
3.13 when accessing .row or .column on a Point built via the Python
constructor.

Fix point_new to mirror point_new_internal: replace PyTuple_Pack +
Py_SET_TYPE with PyTuple_New + PyTuple_SET_ITEM + PyObject_Init.

Fixes bdc2367 ('feat!: add edit method to point & range').
@haxtibal haxtibal force-pushed the bugfix/point_refcnt branch from 6f31f0e to 645a28e Compare July 7, 2026 22:06
@haxtibal

haxtibal commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Please remove the reproducers.

Yes, sorry, committing them was an oversight. I removed them also from the commit message because I first thought you were referring to that. Let me know if I should bring them back in the commit message.

@ObserverOfTime ObserverOfTime merged commit afb3836 into tree-sitter:master Jul 8, 2026
29 checks passed
@ObserverOfTime

Copy link
Copy Markdown
Member

Thank you!

@ObserverOfTime ObserverOfTime changed the title Fix reference counting issues in Point(), causing resource leak and use after free fix(point): fix reference counting issues Jul 8, 2026
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.

2 participants