Skip to content

add_long() leaks one reference per enum value (pyint.release() after PyDict_SetItemString) #257

@devdanzin

Description

@devdanzin

add_long() in enumtypes.cpp:33-47 leaks one PyLong reference per enum constant. PyDict_SetItemString does NOT steal references — it increments the refcount internally. After the call succeeds, pyint.release() drops cppy's ownership without decrementing, orphaning the original reference.

Current code (enumtypes.cpp:41-46):

if( PyDict_SetItemString( dict_ptr.get(), name, pyint.get() ) != 0 )
{
    return false;
}
pyint.release(); // Release the reference since the operation succeeded

The comment "Release the reference since the operation succeeded" reveals a misunderstanding — PyDict_SetItemString added its own reference, so the caller's reference should be decremented, not orphaned.

This function is called ~100+ times during init_enumtypes() (once per enum value across 10 enum types), leaking one PyLong per call. For small integers (-5 to 256), the leak is benign (CPython caches them), but values outside that range leak ~28 bytes each.

Fix — just remove pyint.release():

if( PyDict_SetItemString( dict_ptr.get(), name, pyint.get() ) != 0 )
{
    return false;
}
// Let cppy::ptr destructor decref correctly.
// PyDict_SetItemString already added its own reference.
return true;

Found by cext-review-toolkit.

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