#define LDAP_MEMORY_DEBUG and SLAP_NO_SL_MALLOC breaks slapd in a number of places. Some of the fixes are straightforward, but others require more sweeping changes - or leaving LDAP_MEMORY_DEBUG useless, which it has been for some time anyway.
However the LDAP_MEMORY_DEBUG troubles match a Windows bug: According to ITS#4901, Windows gets heap corruption unless mallocs done in one DLL are balanced by frees done from the same DLL.
(I'll summarize memory management at the end, so the uninitiated can have some clue what I'm talking about.)
The main problem is memory allocated with malloc(), either in slapd or a library - in particular librewrite. proto-slap.h does #define free ch_free unless CH_FREE is #defined. ch_free(malloc(x)) ends up calling ber_memfree, and LDAP_MEMORY_DEBUG breaks ber_memfree(malloc(x)). With Windows, the freeing DLL will be liblber instead of librewrite or whatever.
The simplest fix looks like a global search-and-replace with malloc & co -> ber_memalloc & co except leaving free (-> ch_free) alone in slapd. (Or use LDAP_MALLOC, LBER_MALLOC and SLAP_MALLOC and friends instead. They all expand to ber_memalloc & co.) Is there a reason why we use both malloc() and ber_memalloc()? Functionality aside, it also makes the code harder to read (and to search for bugs).
I think it should be done in librewrite at least, since it is used to insert data into ber_memalloced data structures in slapd's.
I suppose such a change could break some Windows module which by somehow explicitly uses _current_ free vs ber_memfree vs ber_memfree_x correctly - in particular if it uses librewrite as a library outside of slapd. Should we worry? Maybe librewrite should have its own memory handler functions which can be overridden like liblber's.
Regarding the '#define free ch_free' in slapd, I'm not convinced that is a good idea. I'm sure it has saved some code which wrote free where it should have written ch_free, but it also makes it even harder to see what is going on - and apparently it can break slapd modules that use malloc() - free() on Windows. Maybe we should begin to phase it out. (First stage: /free/ch_free/ in slapd, #define CH_FREE in all slapd .c files, and make the #define free ch_free in slap.h cause some warning. Then wait indefinitely for modules to follow suit.)
Summary of OpenLDAP memory management, as I understand it -- Some memory is allocated with plain malloc, but most via ber_mem*() functions in liblber. Of those, the ones ending with "_x" take an extra "context" argument. If you pass a non-NULL context and you have set malloc handler functions in liblber, ber_*_x() call these with the context. Otherwise they call plain malloc() co.
slapd also has thread-local malloc heaps, used by slap_sl_malloc() & co. A thread can have a context, which has a reference to the thread's heap. Threads must not free/alloc in other threads' heaps. This avoids locks or mutexes which malloc() needs to ensure that two concurrent malloc()s do not corrupt malloc()'s heap. Slapd can use them for memory which gets allocated and freed while handling a single request (which gets handled by a single thread), I think.
slapd sets slap_sl_free() co or wrappers around them as memory handlers, and a special ch_free() for the free() handler.
Since it can be a bit hard to keep track of which memory comes from where, ch_free() fetches the current thread's context if passed a NULL context. Then it calls slap_sl_free if there is a context, ber_memfree otherwise. slap_sl_free in turn checks if the memory to be freed came from the context's heap, otherwise it passes it on to ber_memfree() without a context. With the '#define free ch_free', a free/ch_free/slap_sl_free/ber_memfree_x() ends up in the right place. Except if you try to free another thread's memory, or use ber_memfree[_x]() without a context to free a thread's memory, or try to free something from a plain malloc() on Windows.
Oh, and finally there are wrapper functions and macros. LBER_MALLOC, LDAP_MALLOC, SLAP_MALLOC and friends, which expand to ber_memalloc & co. ch_malloc() and friends in slapd, which check that the malloc was successful and exit otherwise. (Naughty, we really ought to phase out that someday.)