@@ -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