Memory leak in ev.c, the second
Alexander Klauer
Alexander.Klauer at itwm.fraunhofer.de
Thu Feb 21 10:39:20 CET 2013
Hi,
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 itwm.fraunhofer.de> 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
below.
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
realloc().
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,
Alexander
-------------- next part --------------
A non-text attachment was scrubbed...
Name: libev.c
Type: text/x-csrc
Size: 491 bytes
Desc: not available
URL: <http://lists.schmorp.de/pipermail/libev/attachments/20130221/c56a551d/attachment.c>
More information about the libev
mailing list