Hello!
I've been working for a few months on a bare-metal Kinetis project, using Processor Expert to provide the HAL. I'm using CW MCU 10.5.
What initially appeared to be a bug in my own code (four bytes being assigned random values in the middle of a buffer), actually translated into what looks to me as a bug in the malloc() routine.
/* Second: couldn't find a buffer that would fit. attempt to merge two existing buffers to make do. */ /* nbytes cannot fit into struct m_buff -> size */ if ( MAX_M_BUFF < nbytes ) { return NULL; } p = head; while ( NULL != p ) { if ( NO == p->used ) { struct m_buff* look_ahd = p->lnk; size_t tot_room = p->size; while ((NULL != look_ahd) && (NO == look_ahd->used) && (tot_room < nbytes)) { tot_room += ((size_t)look_ahd->size + sizeof(struct m_buff)); look_ahd = look_ahd->lnk; } if ( tot_room >= nbytes ) { LOCALALLOC(p, nbytes) p->lnk = look_ahd; p->used = YES; p->size = tot_room; #if HEAP_GROWS if ((look_ahd != NULL) && (look_ahd->lnk == NULL)) tail = &p->lnk; #endif #if defined(_REENTRANT) && _REENTRANT __end_critical_region ( malloc_pool_access ); #endif return ((char_t*) p ) + sizeof( struct m_buff ); } } p = p->lnk; }
Basically, if multiple free buffers are merged to satisfy the need for a bigger buffer, the tail will keep pointing to where an old 'buffer' used to be. The effect of this is that, when a new buffer is allocated using sbrk(),
#if HEAP_GROWS *tail = new_buff; new_buff->lnk = NULL; tail = &new_buff->lnk; #else
the instruction at line 2 will write the address of the new buffer right in the middle of a previously allocated area.
This is the current sequence of mallocs/free, I will try to narrow it down to a simpler test-case tomorrow:
a = malloc(8);
b = malloc(16);
free(a);
free(b);
a = malloc(1140);
b = malloc(16);
free(a);
free(b);
a = malloc(200);
b = malloc(16);
free(a);
free(b);
a = malloc(8);
b = malloc(16);
free(a);
free(b);
a = malloc(1140);
b = malloc(16); -> This is when 'tail' overwrites bytes in the middle of my buffer.
Wondering if this is something that the development team is aware of and if they have a fix.
Thanks,
Alex
已解决! 转到解答。
I've managed to fix this by changing:
if ((look_ahd != NULL) && (look_ahd->lnk == NULL))
tail = &p->lnk;
to
if (look_ahd == NULL)
tail = &p->lnk;
in alloc.c, line 468.
Basically, the case that was missed was if all the existing buckets were merged into a bigger one. This is covered by testing if 'look_ahd' is NULL, thus meaning that there are no more buckets. If there are (look_ahd != NULL), then there's no point in modifying the 'tail' variable as it already points to the correct bucket.
Alex
I've managed to fix this by changing:
if ((look_ahd != NULL) && (look_ahd->lnk == NULL))
tail = &p->lnk;
to
if (look_ahd == NULL)
tail = &p->lnk;
in alloc.c, line 468.
Basically, the case that was missed was if all the existing buckets were merged into a bigger one. This is covered by testing if 'look_ahd' is NULL, thus meaning that there are no more buckets. If there are (look_ahd != NULL), then there's no point in modifying the 'tail' variable as it already points to the correct bucket.
Alex
Hi Carlos,
Yes, I am using Kinetis K22F120 and GCC as the compiler. However, given the nature of the problem and the solution I've found, I think the issue is in malloc's handling of merging the free buffers/buckets, as posted above.
Alex