Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

312 lines
9.2 KiB

  1. /***
  2. *align.c - Aligned allocation, reallocation or freeing of memory in the heap
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Defines the _aligned_malloc(),
  8. * _aligned_realloc(),
  9. * _aligned_offset_malloc(),
  10. * _aligned_offset_realloc() and
  11. * _aligned_free() functions.
  12. *
  13. *Revision History:
  14. * 11-05-99 GB Module created.
  15. * 01-04-00 GB renamed the routines.
  16. * _aligned_routine -> _aligned_routine_base
  17. * 01-19-00 GB Fixed _alingned_realloc and _aligned_offset_realloc
  18. * to move the memblock while realloc.
  19. * 03-20-00 GB Rewrite _aligned_malloc and _aligned_realloc making
  20. * use of their offset counterparts with offset=0
  21. * 06-21-00 GB Changed _aligned_realloc so as to mimic realloc.
  22. *
  23. *******************************************************************************/
  24. #include <dbgint.h>
  25. #include <crtdbg.h>
  26. #include <errno.h>
  27. #include <string.h>
  28. #include <malloc.h>
  29. #include <stddef.h>
  30. #include <stdlib.h>
  31. #define IS_2_POW_N(X) (((X)&(X-1)) == 0)
  32. #define PTR_SZ sizeof(void *)
  33. /***
  34. *
  35. * |1|___6___|2|3|4|_________5__________|_6_|
  36. *
  37. * 1 -> Pointer to start of the block allocated by malloc.
  38. * 2 -> Value of 1.
  39. * 3 -> Gap used to get 1 aligned on sizeof(void *).
  40. * 4 -> Pointer to the start of data block.
  41. * 4+5 -> Data block.
  42. * 6 -> Wasted memory at rear of data block.
  43. * 6 -> Wasted memory.
  44. *
  45. *******************************************************************************/
  46. /***
  47. * void *_aligned_malloc_base(size_t size, size_t alignment)
  48. * - Get a block of aligned memory from the heap.
  49. *
  50. * Purpose:
  51. * Allocate of block of aligned memory aligned on the alignment of at least
  52. * size bytes from the heap and return a pointer to it.
  53. *
  54. * Entry:
  55. * size_t size - size of block requested
  56. * size_t alignment - alignment of memory
  57. *
  58. * Exit:
  59. * Sucess: Pointer to memory block
  60. * Faliure: Null
  61. *******************************************************************************/
  62. void * __cdecl _aligned_malloc_base(
  63. size_t size,
  64. size_t alignment
  65. )
  66. {
  67. return _aligned_offset_malloc_base(size, alignment, 0);
  68. }
  69. /***
  70. * void *_aligned_offset_malloc_base(size_t size, size_t alignment, int offset)
  71. * - Get a block of memory from the heap.
  72. *
  73. * Purpose:
  74. * Allocate a block of memory which is shifted by offset from alignment of
  75. * at least size bytes from the heap and return a pointer to it.
  76. *
  77. * Entry:
  78. * size_t size - size of block of memory
  79. * size_t alignment - alignment of memory
  80. * size_t offset - offset of memory from the alignment
  81. *
  82. * Exit:
  83. * Sucess: Pointer to memory block
  84. * Faliure: Null
  85. *
  86. *******************************************************************************/
  87. void * __cdecl _aligned_offset_malloc_base(
  88. size_t size,
  89. size_t align,
  90. size_t offset
  91. )
  92. {
  93. uintptr_t ptr, retptr, gap;
  94. if (!IS_2_POW_N(align))
  95. {
  96. errno = EINVAL;
  97. return NULL;
  98. }
  99. if ( offset >= size && offset != 0)
  100. {
  101. errno = EINVAL;
  102. return NULL;
  103. }
  104. align = (align > PTR_SZ ? align : PTR_SZ) -1;
  105. /* gap = number of bytes needed to round up offset to align with PTR_SZ*/
  106. gap = (0 - offset)&(PTR_SZ -1);
  107. if ( (ptr =(uintptr_t)malloc(PTR_SZ +gap +align +size)) == (uintptr_t)NULL)
  108. return NULL;
  109. retptr =((ptr +PTR_SZ +gap +align +offset)&~align)- offset;
  110. ((uintptr_t *)(retptr - gap))[-1] = ptr;
  111. return (void *)retptr;
  112. }
  113. /***
  114. *
  115. * void *_aligned_realloc_base(void * memblock, size_t size, size_t alignment)
  116. * - Reallocate a block of aligned memory from the heap.
  117. *
  118. * Purpose:
  119. * Reallocates of block of aligned memory aligned on the alignment of at
  120. * least size bytes from the heap and return a pointer to it. Size can be
  121. * either greater or less than the original size of the block.
  122. * The reallocation may result in moving the block as well as changing the
  123. * size.
  124. *
  125. * Entry:
  126. * void *memblock - pointer to block in the heap previously allocated by
  127. * call to _aligned_malloc(), _aligned_offset_malloc(),
  128. * _aligned_realloc() or _aligned_offset_realloc().
  129. * size_t size - size of block requested
  130. * size_t alignment - alignment of memory
  131. *
  132. * Exit:
  133. * Sucess: Pointer to re-allocated memory block
  134. * Faliure: Null
  135. *
  136. *******************************************************************************/
  137. void * __cdecl _aligned_realloc_base(
  138. void *memblock,
  139. size_t size,
  140. size_t alignment
  141. )
  142. {
  143. return _aligned_offset_realloc_base(memblock, size, alignment, 0);
  144. }
  145. /***
  146. *
  147. * void *_aligned_offset_realloc_base (void * memblock, size_t size,
  148. * size_t alignment, int offset)
  149. * - Reallocate a block of memory from the heap.
  150. *
  151. * Purpose:
  152. * Reallocates a block of memory which is shifted by offset from
  153. * alignment of at least size bytes from the heap and return a pointer
  154. * to it. Size can be either greater or less than the original size of the
  155. * block.
  156. *
  157. * Entry:
  158. * void *memblock - pointer to block in the heap previously allocated by
  159. * call to _aligned_malloc(), _aligned_offset_malloc(),
  160. * _aligned_realloc() or _aligned_offset_realloc().
  161. * size_t size - size of block of memory
  162. * size_t alignment - alignment of memory
  163. * size_t offset - offset of memory from the alignment
  164. *
  165. * Exit:
  166. * Sucess: Pointer to the re-allocated memory block
  167. * Faliure: Null
  168. *
  169. *******************************************************************************/
  170. void * __cdecl _aligned_offset_realloc_base(
  171. void *memblock,
  172. size_t size,
  173. size_t align,
  174. size_t offset
  175. )
  176. {
  177. uintptr_t ptr, retptr, gap, stptr, diff;
  178. uintptr_t movsz, reqsz;
  179. int bFree = 0;
  180. if (memblock == NULL)
  181. {
  182. return _aligned_offset_malloc_base(size, align, offset);
  183. }
  184. if ( size == 0)
  185. {
  186. _aligned_free_base(memblock);
  187. return NULL;
  188. }
  189. if ( offset >= size && offset != 0)
  190. {
  191. errno = EINVAL;
  192. return NULL;
  193. }
  194. stptr = (uintptr_t)memblock;
  195. /* ptr points to the pointer to starting of the memory block */
  196. stptr = (stptr & ~(PTR_SZ -1)) - PTR_SZ;
  197. /* ptr is the pointer to the start of memory block*/
  198. stptr = *((uintptr_t *)stptr);
  199. if (!IS_2_POW_N(align))
  200. {
  201. errno = EINVAL;
  202. return NULL;
  203. }
  204. align = (align > PTR_SZ ? align : PTR_SZ) -1;
  205. /* gap = number of bytes needed to round up offset to align with PTR_SZ*/
  206. gap = (0 -offset)&(PTR_SZ -1);
  207. diff = (uintptr_t)memblock - stptr;
  208. /* Mov size is min of the size of data available and sizw requested.
  209. */
  210. movsz = _msize((void *)stptr) - ((uintptr_t)memblock - stptr);
  211. movsz = movsz > size? size: movsz;
  212. reqsz = PTR_SZ +gap +align +size;
  213. /* First check if we can expand(reducing or expanding using expand) data
  214. * safely, ie no data is lost. eg, reducing alignment and keeping size
  215. * same might result in loss of data at the tail of data block while
  216. * expanding.
  217. *
  218. * If no, use malloc to allocate the new data and move data.
  219. *
  220. * If yes, expand and then check if we need to move the data.
  221. */
  222. if ((stptr +align +PTR_SZ +gap)<(uintptr_t)memblock)
  223. {
  224. if ((ptr = (uintptr_t)malloc(reqsz)) == (uintptr_t) NULL)
  225. return NULL;
  226. bFree = 1;
  227. }
  228. else
  229. {
  230. if ((ptr = (uintptr_t)_expand((void *)stptr, reqsz)) == (uintptr_t)NULL)
  231. {
  232. if ((ptr = (uintptr_t)malloc(reqsz)) == (uintptr_t) NULL)
  233. return NULL;
  234. bFree = 1;
  235. }
  236. else
  237. stptr = ptr;
  238. }
  239. if ( ptr == ((uintptr_t)memblock - diff)
  240. && !( ((size_t)memblock + gap +offset) & ~(align) ))
  241. {
  242. return memblock;
  243. }
  244. retptr =((ptr +PTR_SZ +gap +align +offset)&~align)- offset;
  245. memmove((void *)retptr, (void *)(stptr + diff), movsz);
  246. if ( bFree)
  247. free ((void *)stptr);
  248. ((uintptr_t *)(retptr - gap))[-1] = ptr;
  249. return (void *)retptr;
  250. }
  251. /***
  252. *
  253. * void *_aligned_free_base(void *memblock)
  254. * - Free the memory which was allocated using _aligned_malloc or
  255. * _aligned_offset_memory
  256. *
  257. * Purpose:
  258. * Frees the algned memory block which was allocated using _aligned_malloc
  259. * or _aligned_memory.
  260. *
  261. * Entry:
  262. * void * memblock - pointer to the block of memory
  263. *
  264. *******************************************************************************/
  265. void __cdecl _aligned_free_base(void *memblock)
  266. {
  267. uintptr_t ptr;
  268. if (memblock == NULL)
  269. return;
  270. ptr = (uintptr_t)memblock;
  271. /* ptr points to the pointer to starting of the memory block */
  272. ptr = (ptr & ~(PTR_SZ -1)) - PTR_SZ;
  273. /* ptr is the pointer to the start of memory block*/
  274. ptr = *((uintptr_t *)ptr);
  275. free((void *)ptr);
  276. }