LDAPmessage_to_python() leaks the per-entry attrdict (and, on one path, the pyctrls list) on three error paths. Each object is a new reference that the success path releases at the end of the loop iteration, but these early return paths skip that cleanup.
File: Modules/message.c
Function: LDAPmessage_to_python
attrdict is created near the top of each entry iteration:
attrdict = PyDict_New();
if (attrdict == NULL) { ... }
1. ldap_get_entry_controls() failure — leaks attrdict
rc = ldap_get_entry_controls(ld, entry, &serverctrls);
if (rc) {
Py_DECREF(result);
ldap_msgfree(m);
ldap_memfree(dn);
return LDAPerror(ld); /* attrdict leaked */
}
2. LDAPControls_to_List() failure — leaks attrdict
if (!(pyctrls = LDAPControls_to_List(serverctrls))) {
int err = LDAP_NO_MEMORY;
ldap_set_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
Py_DECREF(result);
ldap_msgfree(m);
ldap_memfree(dn);
ldap_controls_free(serverctrls);
return LDAPerror(ld); /* attrdict leaked */
}
3. PyUnicode_FromString(dn) failure — leaks attrdict and pyctrls
pydn = PyUnicode_FromString(dn);
if (pydn == NULL) {
Py_DECREF(result);
ldap_msgfree(m);
ldap_memfree(dn);
return NULL; /* attrdict and pyctrls leaked */
}
At this last site both attrdict (from PyDict_New()) and pyctrls (from LDAPControls_to_List()) are owned local references — the normal path releases both a few lines later (Py_DECREF(attrdict); Py_XDECREF(pyctrls);). The DN conversion can fail on a non-UTF-8 distinguished name, so this is more than an OOM-only path.
Suggested fix: release the owned objects on each path, e.g. for site 3:
if (pydn == NULL) {
Py_DECREF(attrdict);
Py_XDECREF(pyctrls);
Py_DECREF(result);
ldap_msgfree(m);
ldap_memfree(dn);
return NULL;
}
and add Py_DECREF(attrdict); to sites 1 and 2.
LDAPmessage_to_python() leaks the per-entry attrdict (and, on one path, the pyctrls list) on three error paths. Each object is a new reference that the success path releases at the end of the loop iteration, but these early return paths skip that cleanup.
File: Modules/message.c
Function: LDAPmessage_to_python
attrdict is created near the top of each entry iteration:
1. ldap_get_entry_controls() failure — leaks attrdict
2. LDAPControls_to_List() failure — leaks attrdict
3. PyUnicode_FromString(dn) failure — leaks attrdict and pyctrls
At this last site both attrdict (from PyDict_New()) and pyctrls (from LDAPControls_to_List()) are owned local references — the normal path releases both a few lines later (Py_DECREF(attrdict); Py_XDECREF(pyctrls);). The DN conversion can fail on a non-UTF-8 distinguished name, so this is more than an OOM-only path.
Suggested fix: release the owned objects on each path, e.g. for site 3:
and add Py_DECREF(attrdict); to sites 1 and 2.