Skip to content

Commit

Permalink
F_MALLOC: Recover from double pointer free
Browse files Browse the repository at this point in the history
This patch makes F_MALLOC more robust in production by avoiding memory
corruption in case of double free operations. Previously, the hash state
would immediately get corrupted on such operations, and it would only be
a matter of time before the allocator would crash in some random place
with a useless backtrace resembling:

\#0  0x0000000000507209 in fm_remove_free (qm=0x7f7d578d2010, size=56) at
mem/f_malloc.c:200
200          *pf=n->u.nxt_free;

When DBG_MALLOC is defined, F_MALLOC will now abort() on a double free,
similar to QM_MALLOC.
  • Loading branch information
liviuchircu committed Feb 15, 2018
1 parent c77dac5 commit 2254d00
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 4 deletions.
21 changes: 17 additions & 4 deletions mem/f_malloc.c
Expand Up @@ -390,7 +390,8 @@ void* fm_malloc(struct fm_block* qm, unsigned long size)
{
n = FRAG_NEXT(frag);

if ( ((char*)n < (char*)qm->last_frag) && n->prev && frag->prev )
if (((char*)n < (char*)qm->last_frag) &&
frag_is_free(n) && frag_is_free(frag))
{
/* detach frag*/
fm_remove_free(qm, frag);
Expand All @@ -417,7 +418,7 @@ void* fm_malloc(struct fm_block* qm, unsigned long size)
n = FRAG_NEXT(frag);
}
while
( ((char*)n < (char*)qm->last_frag) && n->prev);
( ((char*)n < (char*)qm->last_frag) && frag_is_free(n));

fm_insert_free(qm,frag);

Expand Down Expand Up @@ -493,6 +494,18 @@ void fm_free(struct fm_block* qm, void* p)
}
f=(struct fm_frag*) ((char*)p-sizeof(struct fm_frag));

#ifndef F_MALLOC_OPTIMIZATIONS
if (frag_is_free(f)) {
#ifdef DBG_MALLOC
LM_CRIT("freeing already freed pointer (%p), first free: "
"%s: %s(%ld) - aborting\n", p, f->file, f->func, f->line);
abort();
#else
LM_CRIT("freeing already freed pointer (%p) - skipping!\n", p);
return;
#endif
}
#endif
#ifdef DBG_MALLOC
LM_GEN1(memlog, "freeing block alloc'ed from %s: %s(%ld)\n", f->file, f->func,
f->line);
Expand All @@ -505,7 +518,7 @@ void fm_free(struct fm_block* qm, void* p)

n = FRAG_NEXT(f);

if (((char*)n < (char*)qm->last_frag) && n->prev )
if (((char*)n < (char*)qm->last_frag) && frag_is_free(n) )
{

fm_remove_free(qm, n);
Expand Down Expand Up @@ -595,7 +608,7 @@ void* fm_realloc(struct fm_block* qm, void* p, unsigned long size)
diff=size-f->size;
n=FRAG_NEXT(f);

if (((char*)n < (char*)qm->last_frag) && n->prev &&
if (((char*)n < (char*)qm->last_frag) && frag_is_free(n) &&
((n->size+FRAG_OVERHEAD)>=diff)){

fm_remove_free(qm,n);
Expand Down
1 change: 1 addition & 0 deletions mem/f_malloc.h
Expand Up @@ -69,6 +69,7 @@
* +1 .... end - size = 2^k, big buckets */

#define FRAG_OVERHEAD (sizeof(struct fm_frag))
#define frag_is_free(_f) ((_f)->prev)

struct fm_frag{
unsigned long size;
Expand Down

0 comments on commit 2254d00

Please sign in to comment.