Skip to content

Commit

Permalink
Change memory handling in attrs_from_List()
Browse files Browse the repository at this point in the history
attrs_from_List() no longer uses internal buffers of bytes/str PyObject*
to maintain memory. Instead it creates its own copies, which are then
passed to ldap_search_ext() and then cleaned up.

The modification is required for Python 3.7. PyUnicode_AsUTF8() returns
const char* but ldap_search_ext() does not use const.

https://github.com/python-ldap/python-ldap/pull/106
Closes: https://github.com/python-ldap/python-ldap/issues/105
Signed-off-by: Christian Heimes <cheimes@redhat.com>
  • Loading branch information
Christian Heimes authored and Petr Viktorin committed Dec 11, 2017
1 parent 4d3cd7d commit baa091f
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 24 deletions.
8 changes: 8 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ matrix:
env:
- TOXENV=py36
- WITH_GCOV=1
- python: 3.7-dev
env:
- TOXENV=py37
- WITH_GCOV=1
- python: 2.7
env:
- TOXENV=py2-nosasltls
Expand All @@ -44,6 +48,10 @@ matrix:
- WITH_GCOV=1
- python: 3.6
env: TOXENV=doc
allow_failures:
- env:
- TOXENV=py37
- WITH_GCOV=1

env:
global:
Expand Down
67 changes: 43 additions & 24 deletions Modules/LDAPObject.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include <sasl/sasl.h>
#endif

static void free_attrs(char***, PyObject*);
static void free_attrs(char***);

/* constructor */

Expand Down Expand Up @@ -248,13 +248,10 @@ List_to_LDAPMods( PyObject *list, int no_op ) {
*/

int
attrs_from_List( PyObject *attrlist, char***attrsp, PyObject** seq) {
attrs_from_List( PyObject *attrlist, char***attrsp) {

char **attrs = NULL;
Py_ssize_t i, len;
PyObject *item;

*seq = NULL;
PyObject *seq = NULL;

if (attrlist == Py_None) {
/* None means a NULL attrlist */
Expand All @@ -268,8 +265,16 @@ attrs_from_List( PyObject *attrlist, char***attrsp, PyObject** seq) {
"expected *list* of strings, not a string", attrlist);
goto error;
} else {
*seq = PySequence_Fast(attrlist, "expected list of strings or None");
if (*seq == NULL)
PyObject *item = NULL;
Py_ssize_t i, len, strlen;
#if PY_MAJOR_VERSION >= 3
const char *str;
#else
char *str;
#endif

seq = PySequence_Fast(attrlist, "expected list of strings or None");
if (seq == NULL)
goto error;

len = PySequence_Length(attrlist);
Expand All @@ -280,25 +285,36 @@ attrs_from_List( PyObject *attrlist, char***attrsp, PyObject** seq) {

for (i = 0; i < len; i++) {
attrs[i] = NULL;
item = PySequence_Fast_GET_ITEM(*seq, i);
item = PySequence_Fast_GET_ITEM(seq, i);
if (item == NULL)
goto error;
#if PY_MAJOR_VERSION == 2
/* Encoded by Python to UTF-8 */
/* Encoded in Python to UTF-8 */
if (!PyBytes_Check(item)) {
LDAPerror_TypeError("expected bytes in list", item);
goto error;
}
attrs[i] = PyBytes_AsString(item);
if (PyBytes_AsStringAndSize(item, &str, &strlen) == -1) {
goto error;
}
#else
if (!PyUnicode_Check(item)) {
LDAPerror_TypeError("expected string in list", item);
goto error;
}
attrs[i] = PyUnicode_AsUTF8(item);
str = PyUnicode_AsUTF8AndSize(item, &strlen);
#endif
/* Make a copy. PyBytes_AsString* / PyUnicode_AsUTF8* return
* internal values that must be treated like const char. Python
* 3.7 actually returns a const char.
*/
attrs[i] = (char *)PyMem_NEW(char *, strlen + 1);
if (attrs[i] == NULL)
goto nomem;
memcpy(attrs[i], str, strlen + 1);
}
attrs[len] = NULL;
Py_DECREF(seq);
}

*attrsp = attrs;
Expand All @@ -307,22 +323,26 @@ attrs_from_List( PyObject *attrlist, char***attrsp, PyObject** seq) {
nomem:
PyErr_NoMemory();
error:
free_attrs(&attrs, *seq);
Py_XDECREF(seq);
free_attrs(&attrs);
return 0;
}

/* free memory allocated from above routine */

static void
free_attrs( char*** attrsp, PyObject* seq ) {
free_attrs( char*** attrsp) {
char **attrs = *attrsp;
char **p;

if (attrs != NULL) {
PyMem_DEL(attrs);
*attrsp = NULL;
}
if (attrs == NULL)
return;

Py_XDECREF(seq);
*attrsp = NULL;
for (p = attrs; *p != NULL; p++) {
PyMem_DEL(*p);
}
PyMem_DEL(attrs);
}

/*------------------------------------------------------------
Expand Down Expand Up @@ -1130,7 +1150,6 @@ l_ldap_search_ext( LDAPObject* self, PyObject* args )

PyObject *serverctrls = Py_None;
PyObject *clientctrls = Py_None;
PyObject *attrs_seq = NULL;
LDAPControl** server_ldcs = NULL;
LDAPControl** client_ldcs = NULL;

Expand All @@ -1148,7 +1167,7 @@ l_ldap_search_ext( LDAPObject* self, PyObject* args )
&serverctrls, &clientctrls, &timeout, &sizelimit )) return NULL;
if (not_valid(self)) return NULL;

if (!attrs_from_List( attrlist, &attrs, &attrs_seq ))
if (!attrs_from_List( attrlist, &attrs ))
return NULL;

if (timeout >= 0) {
Expand All @@ -1160,14 +1179,14 @@ l_ldap_search_ext( LDAPObject* self, PyObject* args )

if (!PyNone_Check(serverctrls)) {
if (!LDAPControls_from_object(serverctrls, &server_ldcs)) {
free_attrs( &attrs, attrs_seq);
free_attrs( &attrs );
return NULL;
}
}

if (!PyNone_Check(clientctrls)) {
if (!LDAPControls_from_object(clientctrls, &client_ldcs)) {
free_attrs( &attrs, attrs_seq);
free_attrs( &attrs );
LDAPControl_List_DEL( server_ldcs );
return NULL;
}
Expand All @@ -1178,7 +1197,7 @@ l_ldap_search_ext( LDAPObject* self, PyObject* args )
server_ldcs, client_ldcs, tvp, sizelimit, &msgid );
LDAP_END_ALLOW_THREADS( self );

free_attrs( &attrs, attrs_seq);
free_attrs( &attrs );
LDAPControl_List_DEL( server_ldcs );
LDAPControl_List_DEL( client_ldcs );

Expand Down

0 comments on commit baa091f

Please sign in to comment.