heap_raw_realloc.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. #include <string.h>
  2. #include <assert.h>
  3. #include "private.h"
  4. /*--------------------------------------------------------- */
  5. lub_heap_status_t
  6. lub_heap_raw_realloc(lub_heap_t *this,
  7. char **ptr,
  8. size_t requested_size,
  9. lub_heap_align_t alignment)
  10. {
  11. lub_heap_status_t result = LUB_HEAP_FAILED;
  12. lub_heap_block_t *block = NULL;
  13. words_t words;
  14. char *new_ptr = NULL;
  15. const size_t MIN_SIZE = sizeof(lub_heap_free_block_t);
  16. /* make the minimum alignment leave enough space for
  17. * (sizeof(lub_heap_free_block_t) + sizeof(lub_heap_alloc_block_t) + sizeof(lub_heap_node_t))
  18. * approx 72 bytes on 64-bit architecture
  19. */
  20. const lub_heap_align_t MIN_ALIGN_NON_NATIVE = LUB_HEAP_ALIGN_2_POWER_7;
  21. size_t size = requested_size;
  22. do
  23. {
  24. if(NULL == ptr) break; /* The client MUST give us a pointer to play with */
  25. if(LUB_HEAP_ZERO_ALLOC == *ptr)
  26. {
  27. *ptr = NULL;
  28. }
  29. if(*ptr && (BOOL_FALSE == lub_heap_validate_pointer(this,*ptr)))
  30. {
  31. /* This is not a valid pointer */
  32. result = LUB_HEAP_INVALID_POINTER;
  33. break;
  34. }
  35. /* check the heap integrity */
  36. if(BOOL_FALSE == lub_heap_check_memory(this))
  37. {
  38. result = LUB_HEAP_CORRUPTED;
  39. break;
  40. }
  41. if(size)
  42. {
  43. /* make sure we get enough space for the header/tail */
  44. size += sizeof(lub_heap_alloc_block_t);
  45. /* make sure we are at least natively aligned */
  46. size += (LUB_HEAP_ALIGN_NATIVE-1);
  47. size &= ~(LUB_HEAP_ALIGN_NATIVE-1);
  48. if(size < MIN_SIZE)
  49. {
  50. /*
  51. * we must ensure that any allocated block is at least
  52. * large enough to hold a free block node when it is released
  53. */
  54. size = MIN_SIZE;
  55. }
  56. if(LUB_HEAP_ALIGN_NATIVE != alignment)
  57. {
  58. if(alignment < MIN_ALIGN_NON_NATIVE)
  59. {
  60. /*
  61. * ensure that we always leave enough space
  62. * to be able to collapse the block to the
  63. * right size
  64. */
  65. alignment = MIN_ALIGN_NON_NATIVE;
  66. }
  67. /* add twice the alignment */
  68. size += (alignment << 1);
  69. }
  70. }
  71. words = (size >> 2);
  72. if(requested_size > size)
  73. {
  74. /* the size has wrapped when accounting for overheads */
  75. break;
  76. }
  77. if(NULL != *ptr)
  78. {
  79. /* get reference to the current block */
  80. block = lub_heap_block_from_ptr(*ptr);
  81. /* first of all check this is an allocated block */
  82. if(1 == block->alloc.tag.free)
  83. {
  84. result = LUB_HEAP_DOUBLE_FREE;
  85. break;
  86. }
  87. /* first of all check this is an allocated block */
  88. if(BOOL_FALSE == lub_heap_block_check(block))
  89. {
  90. result = LUB_HEAP_CORRUPTED;
  91. break;
  92. }
  93. /* is the current block large enough for the request */
  94. if(words && (block->alloc.tag.words >= words))
  95. {
  96. lub_heap_block_t *next_block = lub_heap_block_getnext(block);
  97. words_t delta = (block->alloc.tag.words - words);
  98. lub_heap_tag_t *tail;
  99. result = LUB_HEAP_OK;
  100. new_ptr = *ptr;
  101. if(delta && (NULL != next_block) )
  102. {
  103. /* can we graft this spare memory to a following free block? */
  104. if(1 == next_block->free.tag.free)
  105. {
  106. block->alloc.tag.words = words;
  107. tail = lub_heap_block__get_tail(block);
  108. tail->words = words;
  109. tail->free = 0;
  110. tail->segment = 0;
  111. lub_heap_graft_to_bottom(this,
  112. next_block,
  113. &tail[1],
  114. delta,
  115. BOOL_FALSE,
  116. BOOL_FALSE);
  117. this->stats.alloc_bytes -= (delta << 2);
  118. break;
  119. }
  120. }
  121. /* Is there enough space to turn the spare memory into a free block? */
  122. if(delta >= (sizeof(lub_heap_free_block_t) >> 2))
  123. {
  124. tail = lub_heap_block__get_tail(block);
  125. lub_heap_init_free_block(this,
  126. &tail[1-delta],
  127. (delta << 2),
  128. BOOL_FALSE,
  129. tail->segment);
  130. block->alloc.tag.words = words;
  131. tail = lub_heap_block__get_tail(block);
  132. tail->words = words;
  133. tail->free = 0;
  134. tail->segment = 0;
  135. this->stats.alloc_bytes -= (delta << 2);
  136. }
  137. break;
  138. }
  139. else if(words)
  140. {
  141. /* can we simple extend the current allocated block? */
  142. if( (BOOL_TRUE == lub_heap_extend_upwards (this,&block,words))
  143. || (BOOL_TRUE == lub_heap_extend_downwards(this,&block,words))
  144. || (BOOL_TRUE == lub_heap_extend_both_ways(this,&block,words)) )
  145. {
  146. result = LUB_HEAP_OK;
  147. new_ptr = (char*)block->alloc.memory;
  148. break;
  149. }
  150. }
  151. }
  152. if(words && (LUB_HEAP_FAILED == result))
  153. {
  154. /* need to reallocate and copy the data */
  155. new_ptr = lub_heap_new_alloc_block(this,words);
  156. if(NULL != new_ptr)
  157. {
  158. result = LUB_HEAP_OK;
  159. if(NULL != block)
  160. {
  161. /* now copy the old contents across */
  162. memcpy(new_ptr,
  163. (const char*)block->alloc.memory,
  164. (block->alloc.tag.words << 2) - sizeof(lub_heap_alloc_block_t));
  165. }
  166. }
  167. else
  168. {
  169. /* couldn't find the space for the request */
  170. break;
  171. }
  172. }
  173. /* now it's time to release the memory of the old block */
  174. if(NULL != block)
  175. {
  176. words_t old_words = block->alloc.tag.words;
  177. bool_t done = BOOL_FALSE;
  178. /* combine with the next block */
  179. if(LUB_HEAP_OK == lub_heap_merge_with_next(this,block))
  180. {
  181. done = BOOL_TRUE;
  182. }
  183. /* combine with the previous block */
  184. if(LUB_HEAP_OK == lub_heap_merge_with_previous(this,block))
  185. {
  186. done = BOOL_TRUE;
  187. }
  188. if(BOOL_FALSE == done)
  189. {
  190. /* create a new free block */
  191. lub_heap_new_free_block(this,block);
  192. }
  193. result = LUB_HEAP_OK;
  194. --this->stats.alloc_blocks;
  195. this->stats.alloc_bytes -= (old_words << 2);
  196. this->stats.alloc_bytes += sizeof(lub_heap_alloc_block_t);
  197. this->stats.alloc_overhead -= sizeof(lub_heap_alloc_block_t);
  198. }
  199. } while(0);
  200. if(LUB_HEAP_OK == result)
  201. {
  202. unsigned delta;
  203. /* align the block as required */
  204. if(LUB_HEAP_ALIGN_NATIVE != alignment)
  205. {
  206. lub_heap_align_block(this,
  207. alignment,
  208. &new_ptr,
  209. &size);
  210. }
  211. /* revert to client space available */
  212. size -= sizeof(lub_heap_alloc_block_t);
  213. *ptr = new_ptr;
  214. delta = (size - requested_size);
  215. if(*ptr && requested_size && (0 < delta))
  216. {
  217. /* make sure that any excess memory is tainted */
  218. lub_heap_taint_memory(*ptr + requested_size,LUB_HEAP_TAINT_ALLOC,delta);
  219. }
  220. }
  221. else if( (LUB_HEAP_FAILED == result)
  222. && (0 == requested_size)
  223. && (NULL == *ptr))
  224. {
  225. /* freeing zero is always OK */
  226. result = LUB_HEAP_OK;
  227. }
  228. return result;
  229. }
  230. /*--------------------------------------------------------- */