Utility.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. #include "core/Utility.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <threads.h>
  6. #include <time.h>
  7. #include "ErrorSimulator.h"
  8. #include "core/Logger.h"
  9. extern inline size_t coreMaxSize(size_t a, size_t b);
  10. extern inline size_t coreMinSize(size_t a, size_t b);
  11. static CoreExitHandler exitHandler = nullptr;
  12. static void* exitData = nullptr;
  13. static CoreOutOfMemoryHandler outOfMemoryHandler = nullptr;
  14. static void* outOfMemoryData = nullptr;
  15. size_t corePopCount(u64 u) {
  16. static const u64 map[16] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
  17. size_t sum = 0;
  18. for(size_t i = 0; i < sizeof(u64) * 8; i += 4) {
  19. sum += map[(u >> i) & 0xF];
  20. }
  21. return sum;
  22. }
  23. size_t coreToStringSize(const void* p, char* buffer, size_t n) {
  24. int w = snprintf(buffer, n, "%zu", *(const size_t*)p);
  25. return w < 0 ? 0 : (size_t)w;
  26. }
  27. size_t coreToStringInt(const void* p, char* buffer, size_t n) {
  28. int w = snprintf(buffer, n, "%d", *(const int*)p);
  29. return w < 0 ? 0 : (size_t)w;
  30. }
  31. void coreStringAdd(size_t* w, char** buffer, size_t* n, size_t shift) {
  32. *w += shift;
  33. if(*n > shift) {
  34. *buffer += shift;
  35. *n -= shift;
  36. } else {
  37. *n = 0;
  38. }
  39. }
  40. void coreStringAddI(size_t* w, char** buffer, size_t* n, int shift) {
  41. coreStringAdd(w, buffer, n, shift < 0 ? 0 : (size_t)shift);
  42. }
  43. [[noreturn]] void coreExitWithHandler(const char* file, int line, int value) {
  44. if(value != 0) {
  45. file = coreGetShortFileName(file);
  46. CORE_LOG_ERROR("Exit from %s:%d with value %d", file, line, value);
  47. }
  48. if(exitHandler != nullptr) {
  49. exitHandler(value, exitData);
  50. }
  51. exit(value);
  52. }
  53. void coreSetExitHandler(CoreExitHandler eh, void* data) {
  54. exitHandler = eh;
  55. exitData = data;
  56. }
  57. void coreSetOutOfMemoryHandler(CoreOutOfMemoryHandler h, void* data) {
  58. outOfMemoryHandler = h;
  59. outOfMemoryData = data;
  60. }
  61. static void* exitOnNull(void* p, size_t n) {
  62. if(p == nullptr) {
  63. CORE_LOG_ERROR("Out of memory, requested '%zu' bytes", n);
  64. CORE_EXIT(1);
  65. }
  66. return p;
  67. }
  68. static void* coreRealAllocate(size_t n) {
  69. void* p = malloc(n);
  70. while(p == nullptr && outOfMemoryHandler != nullptr) {
  71. outOfMemoryHandler(outOfMemoryData);
  72. p = malloc(n);
  73. }
  74. return exitOnNull(p, n);
  75. }
  76. static void* coreRealReallocate(void* oldP, size_t n) {
  77. if(n <= 0) {
  78. free(oldP);
  79. return nullptr;
  80. }
  81. void* p = realloc(oldP, n);
  82. if(p == nullptr) {
  83. while(p == nullptr && outOfMemoryHandler != nullptr) {
  84. outOfMemoryHandler(outOfMemoryData);
  85. p = realloc(oldP, n);
  86. }
  87. }
  88. return exitOnNull(p, n);
  89. }
  90. static void coreRealFree(void* p) {
  91. free(p);
  92. }
  93. #ifdef CORE_CHECK_MEMORY
  94. static const u8 CANARY[16] = {0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF,
  95. 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF};
  96. struct CoreMemoryInfo;
  97. typedef struct CoreMemoryInfo CoreMemoryInfo;
  98. struct CoreMemoryInfo {
  99. CoreMemoryInfo* next;
  100. CoreMemoryInfo* previous;
  101. size_t size;
  102. int line;
  103. char buffer[64 - 2 * sizeof(void*) - sizeof(size_t) - sizeof(int)];
  104. char canary[sizeof(CANARY)];
  105. };
  106. static_assert(sizeof(CoreMemoryInfo) == 80, "memory info has invalid size");
  107. static CoreMemoryInfo* headMemoryInfo = nullptr;
  108. static void addMemoryInfo(CoreMemoryInfo* info, const char* file, int line,
  109. size_t n) {
  110. info->next = nullptr;
  111. info->previous = nullptr;
  112. info->size = n;
  113. info->line = line;
  114. strncpy(info->buffer, coreGetShortFileName(file), sizeof(info->buffer));
  115. memcpy(info->canary, CANARY, sizeof(CANARY));
  116. memcpy((char*)info + n - sizeof(CANARY), CANARY, sizeof(CANARY));
  117. if(headMemoryInfo == nullptr) {
  118. headMemoryInfo = info;
  119. } else {
  120. headMemoryInfo->previous = info;
  121. info->next = headMemoryInfo;
  122. headMemoryInfo = info;
  123. }
  124. }
  125. static void removeMemoryInfo(CoreMemoryInfo* info) {
  126. if(info->previous == nullptr) {
  127. if(info->next == nullptr) {
  128. headMemoryInfo = nullptr;
  129. } else {
  130. headMemoryInfo = info->next;
  131. info->next->previous = nullptr;
  132. }
  133. } else {
  134. if(info->next == nullptr) {
  135. info->previous->next = nullptr;
  136. } else {
  137. info->previous->next = info->next;
  138. info->next->previous = info->previous;
  139. }
  140. }
  141. }
  142. void* coreDebugAllocate(const char* file, int line, size_t n) {
  143. n += sizeof(CoreMemoryInfo) + sizeof(CANARY);
  144. void* p = coreRealAllocate(n + sizeof(CANARY));
  145. addMemoryInfo(p, file, line, n);
  146. return (char*)p + sizeof(CoreMemoryInfo);
  147. }
  148. void* coreDebugReallocate(const char* file, int line, void* p, size_t n) {
  149. if(n > 0) {
  150. n += sizeof(CoreMemoryInfo) + sizeof(CANARY);
  151. }
  152. void* rp = (void*)p;
  153. if(rp != nullptr) {
  154. rp = (char*)rp - sizeof(CoreMemoryInfo);
  155. removeMemoryInfo(rp);
  156. }
  157. void* np = coreRealReallocate(rp, n);
  158. if(np == nullptr) {
  159. return nullptr;
  160. }
  161. addMemoryInfo(np, file, line, n);
  162. return (char*)np + sizeof(CoreMemoryInfo);
  163. }
  164. static bool checkCanary(void* p) {
  165. return memcmp(p, CANARY, sizeof(CANARY)) != 0;
  166. }
  167. void coreFreeDebug(const char* file, int line, void* p) {
  168. if(p == nullptr) {
  169. return;
  170. }
  171. CoreMemoryInfo* rp = nullptr;
  172. void* w = (char*)p - sizeof(CoreMemoryInfo);
  173. memcpy(&rp, &w, sizeof(rp));
  174. // CoreMemoryInfo* rp = (CoreMemoryInfo*)((char*)p -
  175. // sizeof(CoreMemoryInfo));
  176. if(checkCanary(rp->canary)) {
  177. file = coreGetShortFileName(file);
  178. CORE_LOG_ERROR("Free at %s:%d violated pre canary", file, line);
  179. CORE_EXIT(1);
  180. } else if(checkCanary((char*)rp + rp->size - sizeof(CANARY))) {
  181. file = coreGetShortFileName(file);
  182. CORE_LOG_ERROR("Free at %s:%d violated post canary", file, line);
  183. CORE_EXIT(1);
  184. }
  185. removeMemoryInfo(rp);
  186. coreRealFree(rp);
  187. }
  188. void corePrintMemoryReport() {
  189. for(CoreMemoryInfo* i = headMemoryInfo; i != nullptr; i = i->next) {
  190. CORE_LOG_ERROR("%s:%d was not freed", i->buffer, i->line);
  191. }
  192. }
  193. #else
  194. void* coreAllocate(size_t n) {
  195. return coreRealAllocate(n);
  196. }
  197. void* coreReallocate(void* p, size_t n) {
  198. return coreRealReallocate(p, n);
  199. }
  200. void coreFree(void* p) {
  201. coreRealFree(p);
  202. }
  203. #endif
  204. bool coreSleep(i64 nanos) {
  205. struct timespec t;
  206. t.tv_nsec = nanos % 1'000'000'000;
  207. t.tv_sec = nanos / 1'000'000'000;
  208. return thrd_sleep(&t, nullptr) != 0;
  209. }
  210. i64 coreNanos(void) {
  211. struct timespec ts;
  212. if(timespec_get(&ts, TIME_UTC) == 0 || CORE_TIME_GET_FAIL) {
  213. return -1;
  214. }
  215. return (i64)ts.tv_sec * 1'000'000'000L + (i64)ts.tv_nsec;
  216. }