Skip to content

Commit

Permalink
Fix umm_blocks() (#8429)
Browse files Browse the repository at this point in the history
Extracted fix from upstream for umm_blocks() - On allocations that were too
large, umm_blocks() could return an incorrectly truncated value when the result
is cast to uint16_t.
  • Loading branch information
mhightower83 committed Jan 3, 2022
1 parent b5f3d1d commit e5a214e
Showing 1 changed file with 57 additions and 17 deletions.
74 changes: 57 additions & 17 deletions cores/esp8266/umm_malloc/umm_malloc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,28 +266,68 @@ static umm_heap_context_t *umm_get_ptr_context(void *ptr) {

/* ------------------------------------------------------------------------ */

static uint16_t umm_blocks( size_t size ) {
static uint16_t umm_blocks(size_t size) {

/*
* The calculation of the block size is not too difficult, but there are
* a few little things that we need to be mindful of.
*
* When a block removed from the free list, the space used by the free
* pointers is available for data. That's what the first calculation
* of size is doing.
*/
/*
* The calculation of the block size is not too difficult, but there are
* a few little things that we need to be mindful of.
*
* When a block removed from the free list, the space used by the free
* pointers is available for data. That's what the first calculation
* of size is doing.
*
* We don't check for the special case of (size == 0) here as this needs
* special handling in the caller depending on context. For example when we
* realloc() a block to size 0 it should simply be freed.
*
* We do NOT need to check for allocating more blocks than the heap can
* possibly hold - the allocator figures this out for us.
*
* There are only two cases left to consider:
*
* 1. (size <= body) Obviously this is just one block
* 2. (blocks > (2^15)) This should return ((2^15)) to force a
* failure when the allocator runs
*
* If the requested size is greater that 32677-2 blocks (max block index
* minus the overhead of the top and bottom bookkeeping blocks) then we
* will return an incorrectly truncated value when the result is cast to
* a uint16_t.
*/

if( size <= (sizeof(((umm_block *)0)->body)) )
return( 1 );
if (size <= (sizeof(((umm_block *)0)->body))) {
return 1;
}

/*
* If it's for more than that, then we need to figure out the number of
* additional whole blocks the size of an umm_block are required.
*/
/*
* If it's for more than that, then we need to figure out the number of
* additional whole blocks the size of an umm_block are required, so
* reduce the size request by the number of bytes in the body of the
* first block.
*/

size -= (sizeof(((umm_block *)0)->body));

size -= ( 1 + (sizeof(((umm_block *)0)->body)) );
/* NOTE WELL that we take advantage of the fact that INT16_MAX is the
* number of blocks that we can index in 15 bits :-)
*
* The below expression looks wierd, but it's right. Assuming body
* size of 4 bytes and a block size of 8 bytes:
*
* BYTES (BYTES-BODY) (BYTES-BODY-1)/BLOCKSIZE BLOCKS
* 1 n/a n/a 1
* 5 1 0 2
* 12 8 0 2
* 13 9 1 3
*/

size_t blocks = (2 + ((size - 1) / sizeof(umm_block)));

if (blocks > (INT16_MAX)) {
blocks = INT16_MAX;
}

return( 2 + size/(sizeof(umm_block)) );
return (uint16_t)blocks;
}

/* ------------------------------------------------------------------------ */
Expand Down

0 comments on commit e5a214e

Please sign in to comment.