@@ -266,28 +266,68 @@ static umm_heap_context_t *umm_get_ptr_context(void *ptr) {
266
266
267
267
/* ------------------------------------------------------------------------ */
268
268
269
- static uint16_t umm_blocks ( size_t size ) {
269
+ static uint16_t umm_blocks (size_t size) {
270
270
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
+ */
279
297
280
- if ( size <= (sizeof (((umm_block *)0 )->body )) )
281
- return ( 1 );
298
+ if (size <= (sizeof (((umm_block *)0 )->body ))) {
299
+ return 1 ;
300
+ }
282
301
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 ));
287
310
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
+ }
289
329
290
- return ( 2 + size/( sizeof (umm_block)) ) ;
330
+ return ( uint16_t )blocks ;
291
331
}
292
332
293
333
/* ------------------------------------------------------------------------ */
0 commit comments