Skip to content

Commit 08b0ae9

Browse files
committed
Change memory handling in attrs_from_List()
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. Closes: #105 Signed-off-by: Christian Heimes <cheimes@redhat.com>
1 parent 084ffe0 commit 08b0ae9

File tree

1 file changed

+42
-22
lines changed

1 file changed

+42
-22
lines changed

Modules/LDAPObject.c

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include <sasl/sasl.h>
1717
#endif
1818

19-
static void free_attrs(char***, PyObject*);
19+
static void free_attrs(char***);
2020

2121
/* constructor */
2222

@@ -248,13 +248,10 @@ List_to_LDAPMods( PyObject *list, int no_op ) {
248248
*/
249249

250250
int
251-
attrs_from_List( PyObject *attrlist, char***attrsp, PyObject** seq) {
251+
attrs_from_List( PyObject *attrlist, char***attrsp) {
252252

253253
char **attrs = NULL;
254-
Py_ssize_t i, len;
255-
PyObject *item;
256-
257-
*seq = NULL;
254+
PyObject *seq = NULL;
258255

259256
if (attrlist == Py_None) {
260257
/* None means a NULL attrlist */
@@ -268,8 +265,16 @@ attrs_from_List( PyObject *attrlist, char***attrsp, PyObject** seq) {
268265
"expected *list* of strings, not a string", attrlist);
269266
goto error;
270267
} else {
271-
*seq = PySequence_Fast(attrlist, "expected list of strings or None");
272-
if (*seq == NULL)
268+
PyObject *item = NULL;
269+
Py_ssize_t i, len, strlen;
270+
#if PY_VERSION_HEX >= 0x03070000
271+
const char *str;
272+
#else
273+
char *str;
274+
#endif
275+
276+
seq = PySequence_Fast(attrlist, "expected list of strings or None");
277+
if (seq == NULL)
273278
goto error;
274279

275280
len = PySequence_Length(attrlist);
@@ -280,7 +285,7 @@ attrs_from_List( PyObject *attrlist, char***attrsp, PyObject** seq) {
280285

281286
for (i = 0; i < len; i++) {
282287
attrs[i] = NULL;
283-
item = PySequence_Fast_GET_ITEM(*seq, i);
288+
item = PySequence_Fast_GET_ITEM(seq, i);
284289
if (item == NULL)
285290
goto error;
286291
#if PY_MAJOR_VERSION == 2
@@ -289,16 +294,27 @@ attrs_from_List( PyObject *attrlist, char***attrsp, PyObject** seq) {
289294
LDAPerror_TypeError("expected bytes in list", item);
290295
goto error;
291296
}
292-
attrs[i] = PyBytes_AsString(item);
297+
if (PyBytes_AsStringAndSize(item, &str, &strlen) == -1) {
298+
goto error;
299+
}
293300
#else
294301
if (!PyUnicode_Check(item)) {
295302
LDAPerror_TypeError("expected string in list", item);
296303
goto error;
297304
}
298-
attrs[i] = PyUnicode_AsUTF8(item);
305+
str = PyUnicode_AsUTF8AndSize(item, &strlen);
299306
#endif
307+
/* Make a copy. PyBytes_AsString* / PyUnicode_AsUTF8* return
308+
* internal values that must be treated like const char. Python
309+
* 3.7 actually returns a const char.
310+
*/
311+
attrs[i] = (char *)PyMem_NEW(char *, strlen + 1);
312+
if (attrs[i] == NULL)
313+
goto nomem;
314+
memcpy(attrs[i], str, strlen + 1);
300315
}
301316
attrs[len] = NULL;
317+
Py_DECREF(seq);
302318
}
303319

304320
*attrsp = attrs;
@@ -307,22 +323,26 @@ attrs_from_List( PyObject *attrlist, char***attrsp, PyObject** seq) {
307323
nomem:
308324
PyErr_NoMemory();
309325
error:
310-
free_attrs(&attrs, *seq);
326+
Py_XDECREF(seq);
327+
free_attrs(&attrs);
311328
return 0;
312329
}
313330

314331
/* free memory allocated from above routine */
315332

316333
static void
317-
free_attrs( char*** attrsp, PyObject* seq ) {
334+
free_attrs( char*** attrsp) {
318335
char **attrs = *attrsp;
336+
char **p;
319337

320-
if (attrs != NULL) {
321-
PyMem_DEL(attrs);
322-
*attrsp = NULL;
323-
}
338+
if (attrs == NULL)
339+
return;
324340

325-
Py_XDECREF(seq);
341+
*attrsp = NULL;
342+
for (p = attrs; *p != NULL; p++) {
343+
PyMem_DEL(*p);
344+
}
345+
PyMem_DEL(attrs);
326346
}
327347

328348
/*------------------------------------------------------------
@@ -1148,7 +1168,7 @@ l_ldap_search_ext( LDAPObject* self, PyObject* args )
11481168
&serverctrls, &clientctrls, &timeout, &sizelimit )) return NULL;
11491169
if (not_valid(self)) return NULL;
11501170

1151-
if (!attrs_from_List( attrlist, &attrs, &attrs_seq ))
1171+
if (!attrs_from_List( attrlist, &attrs ))
11521172
return NULL;
11531173

11541174
if (timeout >= 0) {
@@ -1160,14 +1180,14 @@ l_ldap_search_ext( LDAPObject* self, PyObject* args )
11601180

11611181
if (!PyNone_Check(serverctrls)) {
11621182
if (!LDAPControls_from_object(serverctrls, &server_ldcs)) {
1163-
free_attrs( &attrs, attrs_seq);
1183+
free_attrs( &attrs );
11641184
return NULL;
11651185
}
11661186
}
11671187

11681188
if (!PyNone_Check(clientctrls)) {
11691189
if (!LDAPControls_from_object(clientctrls, &client_ldcs)) {
1170-
free_attrs( &attrs, attrs_seq);
1190+
free_attrs( &attrs );
11711191
LDAPControl_List_DEL( server_ldcs );
11721192
return NULL;
11731193
}
@@ -1178,7 +1198,7 @@ l_ldap_search_ext( LDAPObject* self, PyObject* args )
11781198
server_ldcs, client_ldcs, tvp, sizelimit, &msgid );
11791199
LDAP_END_ALLOW_THREADS( self );
11801200

1181-
free_attrs( &attrs, attrs_seq);
1201+
free_attrs( &attrs );
11821202
LDAPControl_List_DEL( server_ldcs );
11831203
LDAPControl_List_DEL( client_ldcs );
11841204

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy