Skip to content

[P2] Message attribute reads and native-call helpers leak Python references #243

Description

@drebbe-intrepid

Bug

The generic SpyMessage getter increments attr_name but does not release it when delegating to PyObject_GenericGetAttr. PyNeoDeviceEx_GetHandle/SetHandle retain new references from PyObject_GetAttrString, and the module-object helpers retain PyImport_ImportModule references. These leaks occur in ordinary repeated reads and API calls.

Reviewed commit: 45167e09de6b886cd451a4245f842c8221349711 (current master on 2026-09-15).
Source: src/object_spy_message.cpp:57; src/object_spy_message.cpp:133; src/methods.cpp:932; src/methods.cpp:794

Reproduction

import ics, sys
m = ics.SpyMessage()
name = ''.join(['Status', 'Bit', 'Field'])
getattr(m, name)
before = sys.getrefcount(name)
for _ in range(1000): getattr(m, name)
print(sys.getrefcount(name) - before)

Observed / expected

Reference count grows by approximately one per read (1,002 over the first 1,000 reads in the isolated run, including interpreter warmup). Independently, 1,000 get_device_status calls against a mock DLL increased the same device handle capsule reference count by exactly 1,000. Expected no reference-count growth after calls complete.

Suggested fix and regression coverage

Balance owned references on every path, including helper failures and SetHandle capsule creation. Remove the unnecessary attr_name INCREF or release it before generic delegation. Add stabilized reference-count regression tests for attribute reads, handle lookups, and module lookups.

Validation environment

Windows x64, CPython 3.14.5, extension rebuilt from the commit above. Hardware-dependent entry points below were exercised with a mock DLL, not a connected device. The existing 30 tests pass despite these findings.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions