check_malloc.g 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. # This file is part of asmc, a bootstrapping OS with minimal seed
  2. # Copyright (C) 2018 Giovanni Mascellani <gio@debian.org>
  3. # https://gitlab.com/giomasce/asmc
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. # You should have received a copy of the GNU General Public License
  13. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. const MALLOC_MAX_NUM 100000
  15. const MALLOC_GUARD_SIZE 32
  16. const MALLOC_GUARD_BYTE 0xd4
  17. const MALLOC_GARBAGE_BYTE 0x5c
  18. $malloc_data
  19. $malloc_num
  20. fun _malloc_init 0 {
  21. if malloc_data 0 == {
  22. @malloc_data MALLOC_MAX_NUM 16 * platform_allocate = ;
  23. }
  24. }
  25. fun malloc 1 {
  26. $size
  27. @size 0 param = ;
  28. _malloc_init ;
  29. # Add two guards
  30. $alloc_size
  31. @alloc_size size MALLOC_GUARD_SIZE + MALLOC_GUARD_SIZE + = ;
  32. # Get memory from platform
  33. $ptr
  34. @ptr alloc_size platform_allocate = ;
  35. ptr 1024 1024 * 100 * < "check_malloc: too much alloc" assert_msg ;
  36. # Compute useful pointers
  37. $buf_begin
  38. $buf_end
  39. $ptr_end
  40. @buf_begin ptr MALLOC_GUARD_SIZE + = ;
  41. @buf_end buf_begin size + = ;
  42. @ptr_end buf_end MALLOC_GUARD_SIZE + = ;
  43. # Bookkeeping
  44. malloc_num MALLOC_MAX_NUM < "malloc: too many mallocations" assert_msg ;
  45. malloc_data malloc_num 16 * + size = ;
  46. malloc_data malloc_num 16 * + 4 + buf_begin = ;
  47. malloc_data malloc_num 16 * + 8 + 0 = ;
  48. malloc_data malloc_num 16 * + 12 + __frame_ptr 4 + ** = ;
  49. @malloc_num malloc_num 1 + = ;
  50. # Debug
  51. # "malloc: " 1 platform_log ;
  52. # ptr itoa 1 platform_log ;
  53. # " / " 1 platform_log ;
  54. # buf_begin itoa 1 platform_log ;
  55. # " / " 1 platform_log ;
  56. # buf_end itoa 1 platform_log ;
  57. # " / " 1 platform_log ;
  58. # ptr_end itoa 1 platform_log ;
  59. # "\n" 1 platform_log ;
  60. # Fill the guards with the guard byte
  61. ptr MALLOC_GUARD_BYTE MALLOC_GUARD_SIZE memset ;
  62. buf_end MALLOC_GUARD_BYTE MALLOC_GUARD_SIZE memset ;
  63. # Fill the allocated zone with garbage bytes, so that the program does not depend on it being nulled
  64. buf_begin MALLOC_GARBAGE_BYTE size memset ;
  65. buf_begin ret ;
  66. }
  67. fun _malloc_find_index 1 {
  68. $ptr
  69. @ptr 0 param = ;
  70. $i
  71. @i 0 = ;
  72. while i malloc_num < {
  73. if malloc_data i 16 * + 4 + ** ptr == {
  74. i ret ;
  75. }
  76. @i i 1 + = ;
  77. }
  78. "Unallocated address: " 1 platform_log ;
  79. ptr itoa 1 platform_log ;
  80. "\n" 1 platform_log ;
  81. 0 "_malloc_find_index: requested memory region was not allocated" assert_msg ;
  82. }
  83. fun free 1 {
  84. $buf_begin
  85. @buf_begin 0 param = ;
  86. if buf_begin 0 == {
  87. ret ;
  88. }
  89. # Find the allocation index
  90. $i
  91. @i buf_begin _malloc_find_index = ;
  92. # Check the region is allocated and mark it as allocated
  93. malloc_data i 16 * + 8 + ** 0 == "free: double free" assert_msg ;
  94. malloc_data i 16 * + 8 + 1 = ;
  95. $size
  96. @size malloc_data i 16 * + ** = ;
  97. # Compute useful pointers
  98. $ptr
  99. $buf_end
  100. $ptr_end
  101. @ptr buf_begin MALLOC_GUARD_SIZE - = ;
  102. @buf_end buf_begin size + = ;
  103. @ptr_end buf_end MALLOC_GUARD_SIZE + = ;
  104. # Debug
  105. # "free: " 1 platform_log ;
  106. # ptr itoa 1 platform_log ;
  107. # " / " 1 platform_log ;
  108. # buf_begin itoa 1 platform_log ;
  109. # " / " 1 platform_log ;
  110. # buf_end itoa 1 platform_log ;
  111. # " / " 1 platform_log ;
  112. # ptr_end itoa 1 platform_log ;
  113. # "\n" 1 platform_log ;
  114. # Check the guard zones have not been touched
  115. ptr MALLOC_GUARD_BYTE MALLOC_GUARD_SIZE memcheck "free: leading guard zone has been touched" assert_msg ;
  116. buf_end MALLOC_GUARD_BYTE MALLOC_GUARD_SIZE memcheck "free: trailing guard zone has been touched" assert_msg ;
  117. # Fill the allocated zone with guard bytes, to protect against use-after-free
  118. buf_begin MALLOC_GUARD_BYTE size memset ;
  119. }
  120. fun _malloc_get_size 1 {
  121. $ptr
  122. @ptr 0 param = ;
  123. $i
  124. @i ptr _malloc_find_index = ;
  125. malloc_data i 16 * + ** ret ;
  126. }
  127. fun malloc_stats 0 {
  128. $i
  129. @i 0 = ;
  130. $non_freed
  131. @non_freed 0 = ;
  132. $total_size
  133. @total_size 0 = ;
  134. $non_freed_size
  135. @non_freed_size 0 = ;
  136. while i malloc_num < {
  137. $size
  138. $buf_begin
  139. $freed
  140. @size malloc_data i 16 * + ** = ;
  141. @buf_begin malloc_data i 16 * + 4 + ** = ;
  142. @freed malloc_data i 16 * + 8 + ** = ;
  143. # Compute useful pointers
  144. $ptr
  145. $buf_end
  146. $ptr_end
  147. @ptr buf_begin MALLOC_GUARD_SIZE - = ;
  148. @buf_end buf_begin size + = ;
  149. @ptr_end buf_end MALLOC_GUARD_SIZE + = ;
  150. freed 0 == freed 1 == || "malloc_stats: malloc data corruption" assert_msg ;
  151. # Count regions that were never freed
  152. if freed ! {
  153. @non_freed non_freed 1 + = ;
  154. @non_freed_size non_freed_size size + = ;
  155. }
  156. @total_size total_size size + = ;
  157. # Check that nothing was touched after free
  158. if freed {
  159. ptr MALLOC_GUARD_BYTE MALLOC_GUARD_SIZE memcheck "malloc_stats: leading guard zone has been touched after free" assert_msg ;
  160. buf_end MALLOC_GUARD_BYTE MALLOC_GUARD_SIZE memcheck "malloc_stats: trailing guard zone has been touched after free" assert_msg ;
  161. buf_begin MALLOC_GUARD_BYTE size memcheck "malloc_stats: memory region has been touched after free" assert_msg ;
  162. }
  163. @i i 1 + = ;
  164. }
  165. "The program did " 1 platform_log ;
  166. malloc_num itoa 1 platform_log ;
  167. " allocations (totalling " 1 platform_log ;
  168. total_size itoa 1 platform_log ;
  169. " bytes); " 1 platform_log ;
  170. non_freed itoa 1 platform_log ;
  171. " of them were never free-ed (totalling " 1 platform_log ;
  172. non_freed_size itoa 1 platform_log ;
  173. " bytes).\n" 1 platform_log ;
  174. }