This is the mail archive of the
newlib@sourceware.org
mailing list for the newlib project.
Strange malloc() problem, what am I missing
- From: Per-Henrik Lundblom <ph at whatever dot nu>
- To: newlib at sourceware dot org
- Date: Thu, 10 Aug 2006 09:49:54 +0200
- Subject: Strange malloc() problem, what am I missing
Hi,
I'm using newlib in a project involving FreeRTOS running on an ARM7
target (Philips LPC2138, 32kb RAM). I have use pre-compiled GnuARM
toolchain available from www.gnuarm.net running on both Windows and
Linux. The newlib version is 1.14.0.
I have spent the last week trying to sort out a strange problem that
occurs when using malloc() (eg. malloc_r()). In my application I alloc a
few "large" blocks (~1kb) and then continously alloc and free a lot of
small chunks (8-100bytes). I haven't fully understood exactly how the
malloc implementation in newlib works but I will try to describe the
problem:
Eventually a 24 bytes allocated chunk will be free:d and placed in the
24 bytes bin. This is the only chunk in the 24 bytes bin so the two
next/prev chunk pointers in the chunk points to the same location and
that location is the chunk itself.
This chunk eventually is allocated with a malloc(18) which turns out to
a request to a 24 bytes chunk. The code executed is mallocr.c:2357.
victim and q is set and are not equal so the code block starting at line
2374 is executed. The unlink() macro is executed. Here I experience the
strange problem. Unlink doesn't release the chunk from the 24 byte bin
in the __malloc_av_ (av_ in mallocr.c). Because the chunk is the only
chunk in the 24 byte bin I get the impression it should!
Anyway, the chunk is allocated and returned to the application that
writes data to it. The next/prev pointers that where in the "head" of
the chunk when it was free is of course overwritten because this memory
is allocated and returned to the application.
After a while a malloc(8) is requested. This is again seen as a small
request by malloc. The code in the block mallocr.c:2357 is executed. q and
victim is set, but because these are equal, the q and victim is advanced
one bin. But now this bin is still pointing at the chunk that where
allocated to the application previously! The application has overwritten
the next/prev pointers in the chunk and because of this, these pointers
are invalid and results in a data abort on the ARM7 when executing the
unlink() macro.
I have fixed this with a simple if statement checking if all the
conditions mentioned above is true. If yes, the __malloc_av_ bin array
is updated. See patch below.
THE REAL QUESTION IS: What am I missing, have I mis-configured
something? I can't really see such a simple thing beeing a flaw in the
implementation.
--- newlib-1.14.0/newlib/libc/stdlib/mallocr.c 2005-10-07 20:07:26.000000000 +0200
+++ newlib-1.14.0_patched/newlib/libc/stdlib/mallocr.c 2006-08-09 17:07:14.4230 64700 +0200
@@ -2367,6 +2367,7 @@ Void_t* mALLOc(RARG bytes) RDECL size_t
if (victim == q)
{
q = next_bin(q);
+ victim = (mchunkptr) q;
victim = last(q);
}
#endif
@@ -2374,6 +2375,11 @@ Void_t* mALLOc(RARG bytes) RDECL size_t
{
victim_size = chunksize(victim);
unlink(victim, bck, fwd);
+if (victim->fd == victim->bk && last(q) == first(q) && victim->fd ==
last(q))
+{
+ q->fd = q;
+ q->bk = q;
+}
set_inuse_bit_at_offset(victim, victim_size);
check_malloced_chunk(victim, nb);
MALLOC_UNLOCK;
/PH
--
Per-Henrik Lundblom epost: ph@whatever.nu
telefon: 0733-20 71 26 hemsida: www.whatever.nu