malloc.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /*
  2. * heap.c
  3. *
  4. * Copyright (C) 2017 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <monolithium.h>
  22. #define ALLOCATED (1 << 0)
  23. typedef struct
  24. {
  25. uint32_t magic;
  26. uint32_t flags;
  27. size_t size;
  28. } heap_header_t;
  29. __crt_heap_t *__crt_default_heap = NULL;
  30. static void __crt_heap_coalesce(__crt_heap_t *heap)
  31. {
  32. heap_header_t *ptr = (heap_header_t*)heap->base;
  33. heap_header_t *previous = NULL;
  34. while ((uintptr_t)ptr >= (uintptr_t)heap->base && (uintptr_t)ptr < (uintptr_t)heap->base + heap->size)
  35. {
  36. heap_header_t *next = (heap_header_t*)((uintptr_t)ptr + sizeof(heap_header_t) + ptr->size);
  37. if (previous && !(previous->flags & ALLOCATED) && !(ptr->flags & ALLOCATED))
  38. {
  39. if (((uintptr_t)ptr - (uintptr_t)heap->base) == heap->next_offset)
  40. {
  41. heap->next_offset = (uintptr_t)previous - (uintptr_t)heap->base;
  42. }
  43. previous->size += ptr->size + sizeof(heap_header_t);
  44. }
  45. else
  46. {
  47. previous = ptr;
  48. }
  49. ptr = next;
  50. }
  51. }
  52. void *__crt_heap_realloc(__crt_heap_t *heap, void *ptr, size_t alignment, size_t size)
  53. {
  54. if (!alignment || (alignment & (alignment - 1))) return NULL;
  55. heap->lock_mutex_proc(heap->mutex);
  56. if (!(heap->flags & __CRT_HEAP_FLAG_READY))
  57. {
  58. heap_header_t *header = (heap_header_t*)heap->base;
  59. header->magic = heap->magic;
  60. header->flags = 0;
  61. header->size = heap->size - sizeof(heap_header_t);
  62. heap->flags |= __CRT_HEAP_FLAG_READY;
  63. }
  64. if (!size)
  65. {
  66. if (ptr)
  67. {
  68. heap_header_t *header = (heap_header_t*)((uintptr_t)ptr - sizeof(heap_header_t));
  69. if (header->flags & ALLOCATED)
  70. {
  71. header->flags &= ~ALLOCATED;
  72. __crt_heap_coalesce(heap);
  73. }
  74. else
  75. {
  76. heap->problem(__CRT_HEAP_DOUBLE_FREE);
  77. }
  78. }
  79. heap->unlock_mutex_proc(heap->mutex);
  80. return NULL;
  81. }
  82. heap_header_t *source_block = NULL;
  83. if (ptr)
  84. {
  85. heap_header_t *header = (heap_header_t*)((uintptr_t)ptr - sizeof(heap_header_t));
  86. if (!(header->flags & ALLOCATED) || header->magic != heap->magic)
  87. {
  88. heap->problem(__CRT_HEAP_BAD_POINTER);
  89. heap->unlock_mutex_proc(heap->mutex);
  90. return NULL;
  91. }
  92. if (size > header->size)
  93. {
  94. heap_header_t *next = (heap_header_t*)((uintptr_t)ptr + header->size);
  95. if (!(next->flags & ALLOCATED) && (header->size + next->size + sizeof(heap_header_t)) >= size)
  96. {
  97. if (((uintptr_t)next - (uintptr_t)heap->base) == heap->next_offset)
  98. {
  99. heap->next_offset = (uintptr_t)header - (uintptr_t)heap->base;
  100. }
  101. header->size += next->size + sizeof(heap_header_t);
  102. if (heap->flags & __CRT_HEAP_FLAG_ZEROFILL) memset(next, 0, size - header->size - size);
  103. }
  104. else
  105. {
  106. source_block = header;
  107. }
  108. }
  109. if (size < (header->size - sizeof(heap_header_t)))
  110. {
  111. heap_header_t *new_block = (heap_header_t*)((uintptr_t)ptr + size);
  112. new_block->magic = heap->magic;
  113. new_block->flags = 0;
  114. new_block->size = header->size - size - sizeof(heap_header_t);
  115. header->size = size;
  116. __crt_heap_coalesce(heap);
  117. }
  118. if (!source_block)
  119. {
  120. heap->unlock_mutex_proc(heap->mutex);
  121. return ptr;
  122. }
  123. }
  124. heap_header_t *hole = NULL;
  125. if (heap->flags & __CRT_HEAP_FLAG_BESTFIT)
  126. {
  127. heap_header_t *current = (heap_header_t*)heap->base;
  128. size_t minimum_size;
  129. while ((uintptr_t)current < (uintptr_t)heap->base + heap->size)
  130. {
  131. if (current->magic != heap->magic)
  132. {
  133. heap->problem(__CRT_HEAP_CORRUPTED);
  134. heap->unlock_mutex_proc(heap->mutex);
  135. return NULL;
  136. }
  137. if (!(current->flags & ALLOCATED))
  138. {
  139. uintptr_t current_start = (uintptr_t)current + sizeof(heap_header_t);
  140. uintptr_t aligned_start = (current_start + alignment - 1) & ~(alignment - 1);
  141. size_t padding = aligned_start - current_start;
  142. if (current->size > padding)
  143. {
  144. size_t adjusted_size = current->size - padding;
  145. if (adjusted_size >= size && (!hole || adjusted_size < minimum_size))
  146. {
  147. hole = current;
  148. minimum_size = adjusted_size;
  149. }
  150. }
  151. }
  152. heap_header_t *next = (heap_header_t*)((uintptr_t)current + sizeof(heap_header_t) + current->size);
  153. if ((uintptr_t)next <= (uintptr_t)current)
  154. {
  155. heap->problem(__CRT_HEAP_CORRUPTED);
  156. heap->unlock_mutex_proc(heap->mutex);
  157. return NULL;
  158. }
  159. current = next;
  160. }
  161. }
  162. else
  163. {
  164. uintptr_t offset = heap->next_offset;
  165. int cycles = 0;
  166. do
  167. {
  168. heap_header_t *current = (heap_header_t*)(heap->base + offset);
  169. if (current->magic != heap->magic)
  170. {
  171. heap->problem(__CRT_HEAP_CORRUPTED);
  172. heap->unlock_mutex_proc(heap->mutex);
  173. return NULL;
  174. }
  175. if (!(current->flags & ALLOCATED))
  176. {
  177. uintptr_t current_start = (uintptr_t)current + sizeof(heap_header_t);
  178. uintptr_t aligned_start = (current_start + alignment - 1) & ~(alignment - 1);
  179. size_t padding = aligned_start - current_start;
  180. if (current->size >= padding && (current->size - padding) >= size)
  181. {
  182. hole = current;
  183. break;
  184. }
  185. }
  186. offset += sizeof(heap_header_t) + current->size;
  187. if (offset > heap->size)
  188. {
  189. offset = 0;
  190. if (++cycles > 1)
  191. {
  192. heap->problem(__CRT_HEAP_CORRUPTED);
  193. heap->unlock_mutex_proc(heap->mutex);
  194. return NULL;
  195. }
  196. }
  197. }
  198. while (offset != heap->next_offset);
  199. heap->next_offset = offset;
  200. }
  201. if (!hole)
  202. {
  203. heap->problem(__CRT_HEAP_OUT_OF_MEMORY);
  204. heap->unlock_mutex_proc(heap->mutex);
  205. return NULL;
  206. }
  207. int coalesce = 0;
  208. uintptr_t start_address = (uintptr_t)hole + sizeof(heap_header_t);
  209. uintptr_t aligned_start = (start_address + alignment - 1) & ~(alignment - 1);
  210. size_t padding = aligned_start - start_address;
  211. if (padding > sizeof(heap_header_t))
  212. {
  213. heap_header_t *new_block = (heap_header_t*)(aligned_start - sizeof(heap_header_t));
  214. new_block->magic = heap->magic;
  215. new_block->flags = 0;
  216. new_block->size = hole->size - padding;
  217. hole->size -= padding + sizeof(heap_header_t);
  218. hole = new_block;
  219. coalesce = 1;
  220. }
  221. else if (padding)
  222. {
  223. heap_header_t *previous = (heap_header_t*)heap->base;
  224. while ((uintptr_t)previous < (uintptr_t)heap->base + heap->size)
  225. {
  226. heap_header_t *next = (heap_header_t*)((uintptr_t)previous + sizeof(heap_header_t) + previous->size);
  227. if (next == hole) break;
  228. if ((uintptr_t)next <= (uintptr_t)previous)
  229. {
  230. heap->problem(__CRT_HEAP_CORRUPTED);
  231. heap->unlock_mutex_proc(heap->mutex);
  232. return NULL;
  233. }
  234. previous = next;
  235. }
  236. if ((uintptr_t)previous < (uintptr_t)heap->base
  237. || (uintptr_t)previous >= (uintptr_t)heap->base + heap->size
  238. || previous->magic != heap->magic)
  239. {
  240. heap->problem(__CRT_HEAP_CORRUPTED);
  241. heap->unlock_mutex_proc(heap->mutex);
  242. return NULL;
  243. }
  244. previous->size += padding;
  245. heap_header_t *new_block = (heap_header_t*)(aligned_start - sizeof(heap_header_t));
  246. memmove(new_block, hole, sizeof(heap_header_t));
  247. if (heap->next_offset == (uintptr_t)hole - (uintptr_t)heap->base) heap->next_offset += padding;
  248. hole = new_block;
  249. hole->size -= padding;
  250. }
  251. hole->flags |= ALLOCATED;
  252. if (hole->size > sizeof(heap_header_t) && size < (hole->size - sizeof(heap_header_t)))
  253. {
  254. heap_header_t *new_block = (heap_header_t*)((uintptr_t)hole + size + sizeof(heap_header_t));
  255. new_block->magic = heap->magic;
  256. new_block->flags = 0;
  257. new_block->size = hole->size - size - sizeof(heap_header_t);
  258. hole->size = size;
  259. coalesce = 1;
  260. }
  261. void *destination = (void*)((uintptr_t)hole + sizeof(heap_header_t));
  262. if (heap->flags & __CRT_HEAP_FLAG_ZEROFILL) memset(destination, 0, size);
  263. if (source_block)
  264. {
  265. void *source = (void*)((uintptr_t)source_block + sizeof(heap_header_t));
  266. memcpy(destination, source, source_block->size);
  267. source_block->flags &= ~ALLOCATED;
  268. coalesce = 1;
  269. }
  270. if (coalesce) __crt_heap_coalesce(heap);
  271. heap->unlock_mutex_proc(heap->mutex);
  272. return destination;
  273. }
  274. void *aligned_alloc(size_t alignment, size_t size)
  275. {
  276. return __crt_heap_realloc(__crt_default_heap, NULL, alignment, size);
  277. }
  278. void *realloc(void *ptr, size_t size)
  279. {
  280. return __crt_heap_realloc(__crt_default_heap, ptr, sizeof(long), size);
  281. }
  282. void *malloc(size_t size)
  283. {
  284. return __crt_heap_realloc(__crt_default_heap, NULL, sizeof(long), size);
  285. }
  286. void free(void *ptr)
  287. {
  288. __crt_heap_realloc(__crt_default_heap, ptr, sizeof(long), 0);
  289. }
  290. void *calloc(size_t nmemb, size_t size)
  291. {
  292. void *ptr = malloc(nmemb * size);
  293. if (!ptr) return NULL;
  294. memset(ptr, 0, nmemb * size);
  295. return ptr;
  296. }
  297. static void __crt_heap_lock(void *mutex)
  298. {
  299. syscall_wait_mutex((handle_t)mutex, NO_TIMEOUT);
  300. }
  301. static void __crt_heap_unlock(void *mutex)
  302. {
  303. syscall_release_mutex((handle_t)mutex);
  304. }
  305. static void __crt_heap_problem(int problem)
  306. {
  307. // TODO
  308. }
  309. int __crt_initialize_heap(void)
  310. {
  311. static __crt_heap_t heap;
  312. heap.magic = 0x70616548;
  313. heap.base = NULL;
  314. heap.size = 0x10000000;
  315. heap.flags = 0;
  316. heap.next_offset = 0;
  317. heap.lock_mutex_proc = __crt_heap_lock;
  318. heap.unlock_mutex_proc = __crt_heap_unlock;
  319. heap.problem = __crt_heap_problem;
  320. sysret_t status = syscall_create_mutex(NULL, TRUE, (handle_t*)&heap.mutex);
  321. if (status != ERR_SUCCESS) return -1;
  322. status = syscall_alloc_memory(INVALID_HANDLE, &heap.base, heap.size, MEMORY_BLOCK_ACCESSIBLE | MEMORY_BLOCK_WRITABLE);
  323. if (status != ERR_SUCCESS) return -1;
  324. __crt_default_heap = &heap;
  325. return 0;
  326. }