Utility.cpp 6.7 KB

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