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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions