8000 Fix umm_blocks() (#8429) · esp8266/Arduino@e5a214e · GitHub
[go: up one dir, main page]

Skip to content

Commit e5a214e

Browse files
authored
Fix umm_blocks() (#8429)
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.
1 parent b5f3d1d commit e5a214e

File tree

1 file changed

+57
-17
lines changed

1 file changed

+57
-17
lines changed

cores/esp8266/umm_malloc/umm_malloc.cpp

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -266,28 +266,68 @@ static umm_heap_context_t *umm_get_ptr_context(void *ptr) {
266266

267267
/* ------------------------------------------------------------------------ */
268268

269-
static uint16_t umm_blocks( size_t size ) {
269+
static uint16_t umm_blocks(size_t size) {
270270

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

280-
if( size <= (sizeof(((umm_block *)0)->body)) )
281-
return( 1 );
298+
if (size <= (sizeof(((umm_block *)0)->body))) {
299+
return 1;
300+
}
282301

283-
/*
284-
* If it's for more than that, then we need to figure out the number of
285-
* additional whole blocks the size of an umm_block are required.
286-
*/
302+
/*
303+
* If it's for more than that, then we need to figure out the number of
304+
* additional whole blocks the size of an umm_block are required, so
305+
* reduce the size request by the number of bytes in the body of the
306+
* first block.
307+
*/
308+
309+
size -= (sizeof(((umm_block *)0)->body));
287310

288-
size -= ( 1 + (sizeof(((umm_block *)0)->body)) );
311+
/* NOTE WELL that we take advantage of the fact that INT16_MAX is the
312+
* number of blocks that we can index in 15 bits :-)
313+
*
314+
* The below expression looks wierd, but it's right. Assuming body
315+
* size of 4 bytes and a block size of 8 bytes:
316+
*
317+
* BYTES (BYTES-BODY) (BYTES-BODY-1)/BLOCKSIZE BLOCKS
318+
* 1 n/a n/a 1
319+
* 5 1 0 2
320+
* 12 8 0 2
321+
* 13 9 1 3
322+
*/
323+
324+
size_t blocks = (2 + ((size - 1) / sizeof(umm_block)));
325+
326+
if (blocks > (INT16_MAX)) {
327+
blocks = INT16_MAX;
328+
}
289329

290-
return( 2 + size/(sizeof(umm_block)) );
330+
return (uint16_t)blocks;
291331
}
292332

293333
/* ------------------------------------------------------------------------ */

0 commit comments

Comments
 (0)
0