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

Fix reference counting leak in nrnpy_restore_savestate_. #3212

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

1uc
Copy link
Collaborator

@1uc 1uc commented Nov 15, 2024

The facts:

  1. PyByteArray_FromStringAndSize returns a "new reference" 1.
  2. PyObject_CallObject returns a "new reference" 2.
  3. PyTuple_SetItem steals py_data 3.

I like thinking in terms of "relative" or "local" reference counts, by which I mean the number of INCREFs that we can't pair up with a DECREF. Therefore, +1 is one INCREF for which we don't have an associated DECREF. It doesn't mean that the reference count is 1.

Let's analyse py_data first:

  • After PyByteArray_FromStringAndSize it's at +1 (meaning 1 unaccounted INCREF).
  • After Py_INCREF(py_data) it's at +2.
  • By calling PyTuple_SetItem we know 1 DECREF will happen, because it steals py_data. The reference count of py_data is at +1.

Therefore, there's one INCREF which we can't pair up with a DECREF. Consequently, I believe this code leaks py_data.

The analysis of this commit is:

  • We nb::steal the new reference and are at +0 (the dtor will DECREF).
  • In PyTuple_SetItem(..., py_data.release().ptr()) we hand over our reference and are still at +0 (because from now on the dtor won't DECREF anymore).

Let's move on to result, since it's a "new reference" we're responsible for calling DECREF. We nb::steal it and are immediately at +0, because the dtor will call DECREF.

Copy link

codecov bot commented Nov 15, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 67.07%. Comparing base (36084d9) to head (ffeee68).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #3212   +/-   ##
=======================================
  Coverage   67.07%   67.07%           
=======================================
  Files         569      569           
  Lines      111205   111205           
=======================================
  Hits        74593    74593           
  Misses      36612    36612           

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

@bbpbuildbot

This comment has been minimized.

Copy link

✔️ 5b9aa6c -> Azure artifacts URL

@1uc 1uc marked this pull request as ready for review November 15, 2024 12:27
The facts:
  1. `PyByteArray_FromStringAndSize` returns a "new reference" [1].
  2. `PyObject_CallObject` returns a "new reference" [2].
  3. `PyTuple_SetItem` steals `py_data` [3].

Let's analyse `py_data` first:
  * After `PyByteArray_FromStringAndSize` it's at `+1` (meaning 1
    unaccounted INCREF).
  * After `Py_INCREF(py_data)` it's at `+2`.
  * By calling `PyTuple_SetItem` we know 1 DECREF will happen, because
    it steals `py_data`. The reference count of `py_data` is at `+1`.

Therefore, there's one INCREF for which we can't pair up with a DECREF.

Let's move on to `result`, since it's a "new reference" we're
responsible for calling `DECREF`.

[1]: https://docs.python.org/3/c-api/bytearray.html#c.PyByteArray_FromStringAndSize
[2]: https://docs.python.org/3/c-api/call.html#c.PyObject_CallObject
[3]: https://docs.python.org/3/c-api/tuple.html#c.PyTuple_SetItem
@1uc 1uc force-pushed the 1uc/fix-reference-leak-restore branch from 5b9aa6c to ffeee68 Compare November 15, 2024 12:27
Copy link

sonarcloud bot commented Nov 15, 2024

Copy link

✔️ ffeee68 -> Azure artifacts URL

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.

3 participants