Memory leak in ev.c, the second

Alexander Klauer Alexander.Klauer at
Thu Feb 21 10:39:20 CET 2013


On 02/20/2013 06:16 PM, Marc Lehmann wrote:
> On Wed, Feb 20, 2013 at 05:28:57PM +0100, Alexander Klauer <Alexander.Klauer at> wrote:
>> semantics as a call to free(ptr). A C89-conformant implementation may
>> return a unique non-NULL pointer which may be safely passed to
>> free().
> And when does this happen *in libev*? realloc frees the memory for cases
> where the ptr is != 0 and size = 0, which is all that libev relies on. And
> currently, the default allocator calls free in all cases where size == 0
> for portability.

This is correct but it's not enough. The problem is more subtle, and my 
first few posts may have added to the confusion. Sorry about that. Let 
me collect and order the various things which came up during the discussion.

1. The malloc(3) man page by the Linux man pages project, version 3.35, 
dated 2011-09-08 does indeed say about realloc(): "If
the new size is larger than the old size, the added memory will not be
initialized. If ptr is NULL, then the call is equivalent to mal‐
loc(size), for all values of size; if size is equal to zero, and ptr is
not NULL, then the call is equivalent to free(ptr)."
The last assertion is incorrect. See 4. for a proof on concept in libev 

2. The C89 standard says "If the size of the space requested is zero, 
the behavior is implementation-defined; the value returned shall be 
either a null pointer or a unique pointer." The realloc() shipped with 
glibc 2.15 is C89-compliant, taking the second choice. In particular, a 
realloc(ptr, 0) does all that which free(ptr) does, but it does 
something on top: every such call returns a unique non-null pointer, 
which may later be safely passed to free(). So thecalls are not 
equivalent in the strict sense. Yes, the space pointed to by ptr *is* 
effectively freed. However, the C library must keep some 
internalinformation as to which pointers may be passed to free(), and 
it's that information which takes upmemory.

3. The libev default allocator in the current CVS head does the right 
thing bycalling free() when the passed size is zero. However, the libev 
documentation says that the allocator merely has to have "semantics 
[...] identical to the |realloc| C89/SuS/POSIX function" (minor nit: C89 
realloc()'s second parameter has type size_t while the libev allocator 
expects a long), which is not enough.

4. I have attached a proof of concept demonstrating the problem. The 
attached program effectively replaces the libev standard allocator with 

a. Compile/link with gcc -Wall -Wextra -pedantic libev.c 
../libev_cvs/.libs/libev.a -lm
b. Set ulimit -v 262144 or something, lest the OOM killer rears its ugly 
head(on a desktop configuration).
c. Run ./a.out.

On my desktop system (Linux 3.2.0-35-generic #55-Ubuntu SMP x86_64 
x86_64 x86_64 GNU/Linux glibc 2.15), the program runs for a few seconds, 
and then ends with

(libev) cannot allocate 768 bytes, aborting.Aborted (core dumped)

I hope this postclarifies the issue.

Best regards,
-------------- next part --------------
A non-text attachment was scrubbed...
Name: libev.c
Type: text/x-csrc
Size: 491 bytes
Desc: not available
URL: <>

More information about the libev mailing list