Utility.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. module Core.Utility;
  2. import Core.Logger;
  3. import Core.Thread;
  4. import Core.Types;
  5. import Core.Std;
  6. import Core.New;
  7. import Core.ToString;
  8. static Core::ExitHandler exitHandler = nullptr;
  9. static void* exitData = nullptr;
  10. static Core::OutOfMemoryHandler outOfMemoryHandler = nullptr;
  11. static void* outOfMemoryData = nullptr;
  12. [[noreturn]] void Core::exitWithHandler(
  13. int value, const std::source_location& l) noexcept {
  14. if(value != 0) {
  15. const char* file = getShortFileName(l.file_name());
  16. logError("Exit from {}:{} with value {}", file, l.line(), value);
  17. }
  18. if(exitHandler != nullptr) {
  19. exitHandler(value, exitData);
  20. }
  21. exit(value);
  22. }
  23. void Core::setExitHandler(ExitHandler eh, void* data) noexcept {
  24. exitHandler = eh;
  25. exitData = data;
  26. }
  27. void Core::setOutOfMemoryHandler(OutOfMemoryHandler h, void* data) noexcept {
  28. outOfMemoryHandler = h;
  29. outOfMemoryData = data;
  30. std::set_new_handler([]() {
  31. if(outOfMemoryHandler != nullptr) {
  32. outOfMemoryHandler(outOfMemoryData);
  33. } else {
  34. logError("Out of memory");
  35. exitWithHandler(1);
  36. }
  37. });
  38. }
  39. static void* exitOnNull(void* p, size_t n) noexcept {
  40. if(p == nullptr) {
  41. Core::logError("Out of memory, requested '{}' bytes", n);
  42. Core::exitWithHandler(1);
  43. }
  44. return p;
  45. }
  46. static void* realAllocate(size_t n) noexcept {
  47. void* p = malloc(n);
  48. while(p == nullptr && outOfMemoryHandler != nullptr) {
  49. outOfMemoryHandler(outOfMemoryData);
  50. p = malloc(n);
  51. }
  52. return exitOnNull(p, n);
  53. }
  54. static void* realReallocate(void* oldP, size_t n) noexcept {
  55. if(n <= 0) {
  56. free(oldP);
  57. return nullptr;
  58. }
  59. void* p = realloc(oldP, n);
  60. if(p == nullptr) {
  61. while(p == nullptr && outOfMemoryHandler != nullptr) {
  62. outOfMemoryHandler(outOfMemoryData);
  63. p = realloc(oldP, n);
  64. }
  65. }
  66. return exitOnNull(p, n);
  67. }
  68. static void realFree(void* p) noexcept {
  69. free(p);
  70. }
  71. #ifdef CHECK_MEMORY
  72. static const u8 CANARY[16] = {0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF,
  73. 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF};
  74. static Core::Mutex memoryInfoMutex;
  75. struct MemoryInfo {
  76. MemoryInfo* next;
  77. MemoryInfo* previous;
  78. size_t size;
  79. u32 line;
  80. char buffer[64 - 2 * sizeof(void*) - sizeof(size_t) - sizeof(int)];
  81. char canary[sizeof(CANARY)];
  82. };
  83. static_assert(sizeof(MemoryInfo) == 80, "memory info has invalid size");
  84. static MemoryInfo* headMemoryInfo = nullptr;
  85. static void addMemoryInfo(
  86. MemoryInfo* i, const std::source_location& l, size_t n) noexcept {
  87. i->next = nullptr;
  88. i->previous = nullptr;
  89. i->size = n;
  90. i->line = l.line();
  91. Core::StringBase(i->buffer, sizeof(i->buffer))
  92. .add(Core::getShortFileName(l.file_name()));
  93. memcpy(i->canary, CANARY, sizeof(CANARY));
  94. memcpy(reinterpret_cast<char*>(i) + n, CANARY, sizeof(CANARY));
  95. Core::MutexGuard mg(memoryInfoMutex);
  96. if(headMemoryInfo == nullptr) {
  97. headMemoryInfo = i;
  98. } else {
  99. headMemoryInfo->previous = i;
  100. i->next = headMemoryInfo;
  101. headMemoryInfo = i;
  102. }
  103. }
  104. static void removeMemoryInfo(MemoryInfo* info) noexcept {
  105. Core::MutexGuard mg(memoryInfoMutex);
  106. if(info->previous == nullptr) {
  107. if(info->next == nullptr) {
  108. headMemoryInfo = nullptr;
  109. } else {
  110. headMemoryInfo = info->next;
  111. info->next->previous = nullptr;
  112. }
  113. } else {
  114. if(info->next == nullptr) {
  115. info->previous->next = nullptr;
  116. } else {
  117. info->previous->next = info->next;
  118. info->next->previous = info->previous;
  119. }
  120. }
  121. }
  122. void* Core::allocateRaw(size_t n, const std::source_location& l) noexcept {
  123. n += sizeof(MemoryInfo);
  124. void* p = realAllocate(n + sizeof(CANARY));
  125. addMemoryInfo(static_cast<MemoryInfo*>(p), l, n);
  126. return static_cast<char*>(p) + sizeof(MemoryInfo);
  127. }
  128. void* Core::zeroAllocateRaw(size_t n, const std::source_location& l) noexcept {
  129. void* p = allocateRaw(n, l);
  130. memset(p, 0, n);
  131. return p;
  132. }
  133. void* Core::reallocateRaw(
  134. void* p, size_t n, const std::source_location& l) noexcept {
  135. if(n > 0) {
  136. n += sizeof(MemoryInfo) + sizeof(CANARY);
  137. }
  138. void* rp = p;
  139. if(rp != nullptr) {
  140. rp = static_cast<char*>(rp) - sizeof(MemoryInfo);
  141. removeMemoryInfo(static_cast<MemoryInfo*>(rp));
  142. }
  143. void* np = realReallocate(rp, n);
  144. if(np == nullptr) {
  145. return nullptr;
  146. }
  147. addMemoryInfo(static_cast<MemoryInfo*>(np), l, n - sizeof(CANARY));
  148. return static_cast<char*>(np) + sizeof(MemoryInfo);
  149. }
  150. static bool checkCanary(void* p) noexcept {
  151. return memcmp(p, CANARY, sizeof(CANARY)) != 0;
  152. }
  153. void Core::deallocateRaw(void* p, const std::source_location& l) noexcept {
  154. if(p == nullptr) {
  155. return;
  156. }
  157. void* w = static_cast<char*>(p) - sizeof(MemoryInfo);
  158. MemoryInfo* rp = static_cast<MemoryInfo*>(w);
  159. rp->buffer[sizeof(rp->buffer) - 1] = '\0'; // end might be broken
  160. if(checkCanary(rp->canary)) {
  161. logError(
  162. "Free at {}:{} from {}:{} violated pre canary",
  163. getShortFileName(l.file_name()), l.line(), rp->buffer, rp->line);
  164. exitWithHandler(1, l);
  165. } else if(checkCanary(reinterpret_cast<char*>(rp) + rp->size)) {
  166. logError(
  167. "Free at {}:{} from {}:{} violated post canary",
  168. getShortFileName(l.file_name()), l.line(), rp->buffer, rp->line);
  169. exitWithHandler(1, l);
  170. }
  171. removeMemoryInfo(rp);
  172. realFree(rp);
  173. }
  174. void* operator new(size_t count, const std::source_location& l) noexcept {
  175. return Core::allocateRaw(count, l);
  176. }
  177. void* operator new[](size_t count, const std::source_location& l) noexcept {
  178. return Core::allocateRaw(count, l);
  179. }
  180. #else
  181. void* Core::allocateRaw(size_t n) noexcept {
  182. return realAllocate(n);
  183. }
  184. void* Core::zeroAllocateRaw(size_t n) noexcept {
  185. void* p = allocateRaw(n);
  186. memset(p, 0, n);
  187. return p;
  188. }
  189. void* Core::reallocateRaw(void* p, size_t n) noexcept {
  190. return realReallocate(p, n);
  191. }
  192. void Core::deallocateRaw(void* p) noexcept {
  193. realFree(p);
  194. }
  195. #endif
  196. void Core::printMemoryReport() noexcept {
  197. #ifdef CHECK_MEMORY
  198. Core::MutexGuard mg(memoryInfoMutex);
  199. size_t counter = 0;
  200. for(MemoryInfo* i = headMemoryInfo; i != nullptr; i = i->next) {
  201. if(i->line == 0) {
  202. counter++;
  203. } else {
  204. logError("{}:{} was not freed", i->buffer, i->line);
  205. }
  206. }
  207. if(counter > 0) {
  208. logError("{} unknown entries were not freed", counter);
  209. }
  210. #endif
  211. }