balloc.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. #include <library/cpp/balloc/lib/balloc.h>
  2. #include <errno.h>
  3. namespace NBalloc {
  4. static constexpr size_t ALIVE_SIGNATURE = 0xaULL << 56;
  5. static constexpr size_t DISABLED_SIGNATURE = 0xbULL << 56;
  6. static constexpr size_t SIGNATURE_MASK = 0xfULL << 56;
  7. static constexpr size_t MINIMAL_ALIGNMENT = sizeof(NBalloc::TAllocHeader);
  8. static_assert(((MINIMAL_ALIGNMENT - 1) & MINIMAL_ALIGNMENT) == 0,
  9. "invalid BALLOC_MINIMAL_ALIGNMENT");
  10. static Y_FORCE_INLINE void* Malloc(size_t size) {
  11. TLS& ltls = tls;
  12. size = Align(size, sizeof(TAllocHeader));
  13. if (Y_UNLIKELY(ltls.Mode == Empty || ltls.Mode == ToBeEnabled)) {
  14. Init(ltls);
  15. }
  16. if (Y_LIKELY(ltls.Mode != Disabled)) {
  17. TAllocHeader* allocHeader = AllocateRaw(size, ALIVE_SIGNATURE);
  18. return allocHeader + 1;
  19. } else {
  20. // ltls.Mode == Disabled
  21. const size_t extsize = size + sizeof(TAllocHeader);
  22. TAllocHeader* allocHeader = (TAllocHeader*)LibcMalloc(extsize);
  23. allocHeader->Encode(allocHeader, size, DISABLED_SIGNATURE);
  24. return allocHeader + 1;
  25. }
  26. }
  27. static void Y_FORCE_INLINE Free(void* ptr) {
  28. if (ptr == nullptr) {
  29. return;
  30. }
  31. TAllocHeader* allocHeader = ((TAllocHeader*)ptr) - 1;
  32. size_t size = allocHeader->AllocSize;
  33. const size_t signature = size & SIGNATURE_MASK;
  34. if (Y_LIKELY(signature == ALIVE_SIGNATURE)) {
  35. allocHeader->AllocSize = 0; // abort later on double free
  36. #ifdef DBG_FILL_MEMORY
  37. memset(ptr, 0xde, size - signature);
  38. #endif
  39. FreeRaw(allocHeader->Block);
  40. if (NAllocStats::IsEnabled()) {
  41. NAllocStats::DecThreadAllocStats(size - signature);
  42. }
  43. } else if (signature == DISABLED_SIGNATURE) {
  44. LibcFree(allocHeader->Block);
  45. } else {
  46. NMalloc::AbortFromCorruptedAllocator();
  47. }
  48. }
  49. static bool Y_FORCE_INLINE IsOwnedByBalloc(void* ptr) {
  50. TAllocHeader* allocHeader = ((TAllocHeader*)ptr) - 1;
  51. size_t size = allocHeader->AllocSize;
  52. const size_t signature = size & SIGNATURE_MASK;
  53. if (signature == ALIVE_SIGNATURE) {
  54. return true;
  55. } else if (signature == DISABLED_SIGNATURE) {
  56. return false;
  57. }
  58. NMalloc::AbortFromCorruptedAllocator();
  59. Y_UNREACHABLE();
  60. }
  61. static void Y_FORCE_INLINE Disable() {
  62. #if defined(_musl_)
  63. // just skip it
  64. #else
  65. tls.Mode = Disabled;
  66. #endif
  67. }
  68. static void Y_FORCE_INLINE Enable() {
  69. tls.Mode = ToBeEnabled;
  70. }
  71. static bool Y_FORCE_INLINE IsDisabled() {
  72. return tls.Mode == Disabled;
  73. }
  74. };
  75. #if defined(Y_COVER_PTR)
  76. void* CoverPtr(void* ptr, size_t len) noexcept;
  77. void* UncoverPtr(void* ptr) noexcept;
  78. #endif
  79. extern "C" void* malloc(size_t size) {
  80. #if defined(Y_COVER_PTR)
  81. return CoverPtr(NBalloc::Malloc(size + 32), size);
  82. #else
  83. return NBalloc::Malloc(size);
  84. #endif
  85. }
  86. extern "C" void free(void* data) {
  87. #if defined(Y_COVER_PTR)
  88. NBalloc::Free(UncoverPtr(data));
  89. #else
  90. NBalloc::Free(data);
  91. #endif
  92. }
  93. #if defined(USE_INTELCC) || defined(_darwin_) || defined(_freebsd_) || defined(_STLPORT_VERSION)
  94. #define OP_THROWNOTHING noexcept
  95. #else
  96. #define OP_THROWNOTHING
  97. #endif
  98. void* operator new(size_t size) {
  99. #if defined(Y_COVER_PTR)
  100. return malloc(size);
  101. #else
  102. return NBalloc::Malloc(size);
  103. #endif
  104. }
  105. int posix_memalign(void** memptr, const size_t alignment, const size_t size) {
  106. #if defined(Y_COVER_PTR)
  107. (void)alignment;
  108. *memptr = malloc(size);
  109. return 0;
  110. #else
  111. if (((alignment - 1) & alignment) != 0 || alignment < sizeof(void*)) {
  112. return EINVAL;
  113. }
  114. if (alignment <= NBalloc::MINIMAL_ALIGNMENT) {
  115. *memptr = NBalloc::Malloc(size);
  116. return 0;
  117. }
  118. size_t bigSize = size + alignment - NBalloc::MINIMAL_ALIGNMENT;
  119. void* res = NBalloc::Malloc(bigSize);
  120. void* alignedPtr = (void*)NBalloc::Align((size_t)res, alignment);
  121. if (alignedPtr != res) {
  122. auto oldAllocHeader = (NBalloc::TAllocHeader*)res - 1;
  123. auto newAllocHeader = (NBalloc::TAllocHeader*)alignedPtr - 1;
  124. void* block = oldAllocHeader->Block;
  125. newAllocHeader->Encode(block, size, NBalloc::ALIVE_SIGNATURE);
  126. }
  127. *memptr = alignedPtr;
  128. return 0;
  129. #endif
  130. }
  131. void* operator new(size_t size, const std::nothrow_t&) OP_THROWNOTHING {
  132. #if defined(Y_COVER_PTR)
  133. return malloc(size);
  134. #else
  135. return NBalloc::Malloc(size);
  136. #endif
  137. }
  138. void operator delete(void* p)OP_THROWNOTHING {
  139. #if defined(Y_COVER_PTR)
  140. free(p);
  141. #else
  142. NBalloc::Free(p);
  143. #endif
  144. }
  145. void operator delete(void* p, const std::nothrow_t&)OP_THROWNOTHING {
  146. #if defined(Y_COVER_PTR)
  147. free(p);
  148. #else
  149. NBalloc::Free(p);
  150. #endif
  151. }
  152. void* operator new[](size_t size) {
  153. #if defined(Y_COVER_PTR)
  154. return malloc(size);
  155. #else
  156. return NBalloc::Malloc(size);
  157. #endif
  158. }
  159. void* operator new[](size_t size, const std::nothrow_t&) OP_THROWNOTHING {
  160. #if defined(Y_COVER_PTR)
  161. return malloc(size);
  162. #else
  163. return NBalloc::Malloc(size);
  164. #endif
  165. }
  166. void operator delete[](void* p) OP_THROWNOTHING {
  167. #if defined(Y_COVER_PTR)
  168. free(p);
  169. #else
  170. NBalloc::Free(p);
  171. #endif
  172. }
  173. void operator delete[](void* p, const std::nothrow_t&) OP_THROWNOTHING {
  174. #if defined(Y_COVER_PTR)
  175. free(p);
  176. #else
  177. NBalloc::Free(p);
  178. #endif
  179. }
  180. extern "C" void* calloc(size_t n, size_t elemSize) {
  181. const size_t size = n * elemSize;
  182. if (elemSize != 0 && size / elemSize != n) {
  183. return nullptr;
  184. }
  185. #if defined(Y_COVER_PTR)
  186. void* result = malloc(size);
  187. #else
  188. void* result = NBalloc::Malloc(size);
  189. #endif
  190. if (result) {
  191. memset(result, 0, size);
  192. }
  193. return result;
  194. }
  195. extern "C" void cfree(void* ptr) {
  196. #if defined(Y_COVER_PTR)
  197. free(ptr);
  198. #else
  199. NBalloc::Free(ptr);
  200. #endif
  201. }
  202. #if defined(Y_COVER_PTR)
  203. static inline void* DoRealloc(void* oldPtr, size_t newSize) {
  204. #else
  205. extern "C" void* realloc(void* oldPtr, size_t newSize) {
  206. #endif
  207. if (!oldPtr) {
  208. void* result = NBalloc::Malloc(newSize);
  209. return result;
  210. }
  211. if (newSize == 0) {
  212. NBalloc::Free(oldPtr);
  213. return nullptr;
  214. }
  215. void* newPtr = NBalloc::Malloc(newSize);
  216. if (!newPtr) {
  217. return nullptr;
  218. }
  219. NBalloc::TAllocHeader* header = (NBalloc::TAllocHeader*)oldPtr - 1;
  220. const size_t oldSize = header->AllocSize & ~NBalloc::SIGNATURE_MASK;
  221. const size_t signature = header->AllocSize & NBalloc::SIGNATURE_MASK;
  222. if (Y_LIKELY((signature == NBalloc::ALIVE_SIGNATURE) || (signature == NBalloc::DISABLED_SIGNATURE))) {
  223. memcpy(newPtr, oldPtr, oldSize < newSize ? oldSize : newSize);
  224. NBalloc::Free(oldPtr);
  225. return newPtr;
  226. }
  227. NMalloc::AbortFromCorruptedAllocator();
  228. return nullptr;
  229. }
  230. #if defined(Y_COVER_PTR)
  231. extern "C" void* realloc(void* oldPtr, size_t newSize) {
  232. if (!oldPtr) {
  233. return malloc(newSize);
  234. }
  235. if (!newSize) {
  236. free(oldPtr);
  237. return nullptr;
  238. }
  239. return CoverPtr(DoRealloc(UncoverPtr(oldPtr), newSize + 32), newSize);
  240. }
  241. #endif
  242. // Only for testing purposes. Never use in production.
  243. extern "C" bool IsOwnedByBalloc(void* ptr) {
  244. return NBalloc::IsOwnedByBalloc(ptr);
  245. }
  246. extern "C" bool BallocDisabled() {
  247. return NBalloc::IsDisabled();
  248. }
  249. extern "C" void DisableBalloc() {
  250. NBalloc::Disable();
  251. }
  252. extern "C" void EnableBalloc() {
  253. NBalloc::Enable();
  254. }
  255. extern "C" void* memalign(size_t alignment, size_t size) {
  256. void* ptr;
  257. int res = posix_memalign(&ptr, alignment, size);
  258. return res ? nullptr : ptr;
  259. }
  260. extern "C" void* valloc(size_t size) {
  261. return memalign(NBalloc::PAGE_ELEM, size);
  262. }
  263. #if !defined(_MSC_VER) && !defined(_freebsd_)
  264. // Workaround for pthread_create bug in linux.
  265. extern "C" void* __libc_memalign(size_t alignment, size_t size) {
  266. return memalign(alignment, size);
  267. }
  268. #endif