More memory freeing patches to message.c

Michael Ströder michael at stroeder.com
Thu Jul 12 11:38:49 CEST 2001


HI!

Following some more advice by Stig Venaas (see message below) I've
ifdef'ed some memory freeing calls provided by Steffen in message.c
to keep the source compatible to OpenLDAP 1.2.x libs. I've attached
my recent message.c.

Backwards compability is not assumed to be crucial in the long run
but seems nice if we can achieve it with fairly low efforts.

Ciao, Michael.

-------- Original Message --------
Subject: Re: python-ldap and OpenLDAP 2
Date: Thu, 12 Jul 2001 10:47:35 +0200
From: Stig Venaas <Stig.Venaas at uninett.no>
To: Michael Ströder <michael at stroeder.com>
References: <3B4382DD.C9B6A780 at stroeder.com>
<20010711184821.A6433 at sverresborg.uninett.no>
<3B4C94B9.5885D132 at stroeder.com>
<20010712090618.A7043 at sverresborg.uninett.no>
<3B4D525B.47107DC7 at stroeder.com>

On Thu, Jul 12, 2001 at 09:31:39AM +0200, Michael Ströder wrote:
> Stig Venaas wrote:
> > 
> > These memory leaks was also reported and discussed
> > in the OpenLDAP ITS system a few days ago. Someone reported memory
> > leaks and Kurt and I responded. See
> > http://www.OpenLDAP.org/lists/openldap-bugs/200107/msg00018.html
> > for my respons.
> 
> According to this and Steffen's message the ldap_memfree(attr) and
> ber_free(ber, 0) should be ifdef'ed. What about the free(dn) call?
> 
> Well, we have no problems dropping support for linking against
> OpenLDAP 1.x completely if we will have a really stable version and
> it's clear that we can achieve all goals on this track.

PHP supports OpenLDAP 1.x and others that use the RFC1823 API, as
well as Netscape SDK and OpenLDAP 2.x and others that use the new
API. The same should be possible for Python.

I think I've found a bug in PHP when using old API and
ldap_get_dn().
It's not freed! I've never tested much with old API. The PHP code
looks
like this:

#if ( LDAP_API_VERSION > 2000 ) || HAVE_NSLDAP || WINDOWS
                ldap_memfree(dn);
#endif

For Python you could use:
#if ( LDAP_API_VERSION > 2000 )
                ldap_memfree(dn);
#else
		free(dn);
#endif

ldap_memfree() is currently the same as free() but it should be done
this way anyway. Regarding the other leaks, you can use code like:

#if ( LDAP_API_VERSION > 2000 )
                        ldap_memfree(attribute);
#endif

and

#if ( LDAP_API_VERSION > 2000 )
                if (ber != NULL)
                        ber_free(ber, 0);
#endif

This way it should work with both old and new APIs.

> I have changed the calls to free() to ldap_memfree(), which means
> the
> code will compile only against OpenLDAP 2.0.x, since 1.2 does not
> define ldap_memfree().

Hence the trick above.

Stig
-------------- next part --------------
/* David Leonard <david.leonard at csee.uq.edu.au>, 1999. Public domain. */
/*
 * LDAPMessageObject - wrapper around an LDAPMessage*
 * $Id: message.c,v 1.6 2000/08/18 00:21:46 leonard Exp $
 */

#include "common.h"
#include "message.h"
#include "errors.h"
#include "CIDict.h"

PyObject*
LDAPmessage_to_python( LDAP*ld, LDAPMessage*m )
{
    /* we convert an LDAP message into a python structure.
     * It is always a list of dictionaries.
     * We always free m.
     */

     PyObject* result;
     LDAPMessage* entry;

     result = PyList_New(0);
     if (result == NULL) {
        ldap_msgfree( m );
	return NULL;
     }

     for(entry = ldap_first_entry(ld,m);
         entry != NULL;
	 entry = ldap_next_entry(ld,entry))
     {
	 char *dn;
	 char *attr;
	 BerElement *ber = NULL;
	 PyObject* entrytuple; 
	 PyObject* attrdict; 

	 dn = ldap_get_dn( ld, entry );
	 if (dn == NULL)  {
	     Py_DECREF(result);
             ldap_msgfree( m );
	     return LDAPerror( ld, "ldap_get_dn" );
	 }

#ifdef USE_CIDICT
	 attrdict = CIDict_New();
#else /* use standard python dictionary */
	 attrdict = PyDict_New();
#endif /* !CIDICT */
	 if (attrdict == NULL) {
		Py_DECREF(result);
		ldap_msgfree( m );
#if LDAP_API_VERSION >= 2000
		ldap_memfree(dn);
#else
                free(dn);
#endif
		return NULL;
	 }

	 /* Fill attrdict with lists */
	 for( attr = ldap_first_attribute( ld, entry, &ber );
	      attr != NULL;
	      attr = ldap_next_attribute( ld, entry, ber )
	 ) {
	     PyObject* valuelist;
	     struct berval ** bvals =
	     	ldap_get_values_len( ld, entry, attr );

	     /* Find which list to append to */
	     if ( PyMapping_HasKeyString( attrdict, attr ) ) {
		 valuelist = PyMapping_GetItemString( attrdict, attr );
	     } else {
		 valuelist = PyList_New(0);
		 if (valuelist != NULL && PyMapping_SetItemString(attrdict, 
		     attr, valuelist) == -1) {
			Py_DECREF(valuelist);
			valuelist = NULL;	/* catch error later */
		 }
	     }

	     if (valuelist == NULL) {
		Py_DECREF(attrdict);
		Py_DECREF(result);
#if ( LDAP_API_VERSION > 2000 )
                if (ber != NULL)
                        ber_free(ber, 0);
#endif
		ldap_msgfree( m );
#if LDAP_API_VERSION >= 2000
                ldap_memfree(attr);
		ldap_memfree(dn);
#else
                free(dn);
#endif
		return NULL;
	     }

	     if (bvals != NULL) {
	        int i;
		for (i=0; bvals[i]; i++) {
		    PyObject *valuestr;

		    valuestr = PyString_FromStringAndSize( 
			    bvals[i]->bv_val, bvals[i]->bv_len 
			);
		    if (PyList_Append( valuelist, valuestr ) == -1) {
			Py_DECREF(attrdict);
			Py_DECREF(result);
			Py_DECREF(valuestr);
			Py_DECREF(valuelist);
			ldap_msgfree( m );
#if LDAP_API_VERSION >= 2000
                        ldap_memfree(attr);
		        ldap_memfree(dn);
#else
                        free(dn);
#endif
			return NULL;
		    }
		    Py_DECREF(valuestr);
	    	}
		ldap_value_free_len(bvals);
	     }
	     Py_DECREF( valuelist );
#if LDAP_API_VERSION >= 2000
             ldap_memfree(attr);
#endif
	 }

	 entrytuple = Py_BuildValue("(sO)", dn, attrdict);
#if LDAP_API_VERSION >= 2000
	 ldap_memfree(dn);
#else
         free(dn);
#endif
	 Py_DECREF(attrdict);
	 PyList_Append(result, entrytuple);
	 Py_DECREF(entrytuple);
#if ( LDAP_API_VERSION > 2000 )
         if (ber != NULL)
                 ber_free(ber, 0);
#endif
     }
#if LDAP_API_VERSION >= 2000
     for(entry = ldap_first_reference(ld,m);
         entry != NULL;
	 entry = ldap_next_reference(ld,entry))
     {
         char **refs = NULL;
	 PyObject* entrytuple;
	 PyObject* reflist = PyList_New(0);

	 if (reflist == NULL)  {
	     Py_DECREF(result);
             ldap_msgfree( m );
	     return NULL;
	 }
	 if (ldap_parse_reference(ld, entry, &refs, NULL, 0) != LDAP_SUCCESS) {
	     Py_DECREF(result);
             ldap_msgfree( m );
	     return LDAPerror( ld, "ldap_parse_reference" );
	 }
	 if (refs) {
	     int i;
	     for (i=0; refs[i] != NULL; i++) {
		 PyObject *refstr = PyString_FromString(refs[i]);
		 PyList_Append(reflist, refstr);
		 Py_DECREF(refstr);
	     }
	     ber_memvfree( (void **) refs );
         }
	 entrytuple = Py_BuildValue("(sO)", NULL, reflist);
	 Py_DECREF(reflist);
	 PyList_Append(result, entrytuple);
	 Py_DECREF(entrytuple);
     }
#endif
     ldap_msgfree( m );
     return result;
}


More information about the python-ldap mailing list