LDAPraise_for_message() builds an info dictionary and, if the later LDAPControls_to_List() call fails, returns without releasing it. The error path frees the LDAP-owned resources but not the partially filled Python dict.
File: Modules/constants.c
Function: LDAPraise_for_message
Relevant code:
info = PyDict_New();
if (info == NULL) { ... }
/* ... info is populated with msgtype/msgid/result/desc/errno ... */
if (!(pyctrls = LDAPControls_to_List(serverctrls))) {
int err = LDAP_NO_MEMORY;
ldap_set_option(l, LDAP_OPT_ERROR_NUMBER, &err);
ldap_memfree(matched);
ldap_memfree(error);
ldap_memvfree((void **)refs);
ldap_controls_free(serverctrls);
return PyErr_NoMemory(); /* info leaked */
}
info is a new reference from PyDict_New(). On the normal path it is consumed by PyErr_SetObject(errobj, info); Py_DECREF(info); at the end of the function. On the LDAPControls_to_List() failure path it is never released.
Suggested fix:
if (!(pyctrls = LDAPControls_to_List(serverctrls))) {
int err = LDAP_NO_MEMORY;
ldap_set_option(l, LDAP_OPT_ERROR_NUMBER, &err);
Py_DECREF(info);
ldap_memfree(matched);
ldap_memfree(error);
ldap_memvfree((void **)refs);
ldap_controls_free(serverctrls);
return PyErr_NoMemory();
}Reactions are currently unavailable
LDAPraise_for_message() builds an info dictionary and, if the later LDAPControls_to_List() call fails, returns without releasing it. The error path frees the LDAP-owned resources but not the partially filled Python dict.
File: Modules/constants.c
Function: LDAPraise_for_message
Relevant code:
info is a new reference from PyDict_New(). On the normal path it is consumed by PyErr_SetObject(errobj, info); Py_DECREF(info); at the end of the function. On the LDAPControls_to_List() failure path it is never released.
Suggested fix: