wrappers_c.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. //===-- wrappers_c.inc ------------------------------------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #ifndef SCUDO_PREFIX
  9. #error "Define SCUDO_PREFIX prior to including this file!"
  10. #endif
  11. // malloc-type functions have to be aligned to std::max_align_t. This is
  12. // distinct from (1U << SCUDO_MIN_ALIGNMENT_LOG), since C++ new-type functions
  13. // do not have to abide by the same requirement.
  14. #ifndef SCUDO_MALLOC_ALIGNMENT
  15. #define SCUDO_MALLOC_ALIGNMENT FIRST_32_SECOND_64(8U, 16U)
  16. #endif
  17. static void reportAllocation(void *ptr, size_t size) {
  18. if (SCUDO_ENABLE_HOOKS)
  19. if (__scudo_allocate_hook && ptr)
  20. __scudo_allocate_hook(ptr, size);
  21. }
  22. static void reportDeallocation(void *ptr) {
  23. if (SCUDO_ENABLE_HOOKS)
  24. if (__scudo_deallocate_hook)
  25. __scudo_deallocate_hook(ptr);
  26. }
  27. static void reportReallocAllocation(void *old_ptr, void *new_ptr, size_t size) {
  28. DCHECK_NE(new_ptr, nullptr);
  29. if (SCUDO_ENABLE_HOOKS) {
  30. if (__scudo_realloc_allocate_hook)
  31. __scudo_realloc_allocate_hook(old_ptr, new_ptr, size);
  32. else if (__scudo_allocate_hook)
  33. __scudo_allocate_hook(new_ptr, size);
  34. }
  35. }
  36. static void reportReallocDeallocation(void *old_ptr) {
  37. if (SCUDO_ENABLE_HOOKS) {
  38. if (__scudo_realloc_deallocate_hook)
  39. __scudo_realloc_deallocate_hook(old_ptr);
  40. else if (__scudo_deallocate_hook)
  41. __scudo_deallocate_hook(old_ptr);
  42. }
  43. }
  44. extern "C" {
  45. INTERFACE WEAK void *SCUDO_PREFIX(calloc)(size_t nmemb, size_t size) {
  46. scudo::uptr Product;
  47. if (UNLIKELY(scudo::checkForCallocOverflow(size, nmemb, &Product))) {
  48. if (SCUDO_ALLOCATOR.canReturnNull()) {
  49. errno = ENOMEM;
  50. return nullptr;
  51. }
  52. scudo::reportCallocOverflow(nmemb, size);
  53. }
  54. void *Ptr = SCUDO_ALLOCATOR.allocate(Product, scudo::Chunk::Origin::Malloc,
  55. SCUDO_MALLOC_ALIGNMENT, true);
  56. reportAllocation(Ptr, Product);
  57. return scudo::setErrnoOnNull(Ptr);
  58. }
  59. INTERFACE WEAK void SCUDO_PREFIX(free)(void *ptr) {
  60. reportDeallocation(ptr);
  61. SCUDO_ALLOCATOR.deallocate(ptr, scudo::Chunk::Origin::Malloc);
  62. }
  63. INTERFACE WEAK struct SCUDO_MALLINFO SCUDO_PREFIX(mallinfo)(void) {
  64. struct SCUDO_MALLINFO Info = {};
  65. scudo::StatCounters Stats;
  66. SCUDO_ALLOCATOR.getStats(Stats);
  67. // Space allocated in mmapped regions (bytes)
  68. Info.hblkhd = static_cast<__scudo_mallinfo_data_t>(Stats[scudo::StatMapped]);
  69. // Maximum total allocated space (bytes)
  70. Info.usmblks = Info.hblkhd;
  71. // Space in freed fastbin blocks (bytes)
  72. Info.fsmblks = static_cast<__scudo_mallinfo_data_t>(Stats[scudo::StatFree]);
  73. // Total allocated space (bytes)
  74. Info.uordblks =
  75. static_cast<__scudo_mallinfo_data_t>(Stats[scudo::StatAllocated]);
  76. // Total free space (bytes)
  77. Info.fordblks = Info.fsmblks;
  78. return Info;
  79. }
  80. // On Android, mallinfo2 is an alias of mallinfo, so don't define both.
  81. #if !SCUDO_ANDROID
  82. INTERFACE WEAK struct __scudo_mallinfo2 SCUDO_PREFIX(mallinfo2)(void) {
  83. struct __scudo_mallinfo2 Info = {};
  84. scudo::StatCounters Stats;
  85. SCUDO_ALLOCATOR.getStats(Stats);
  86. // Space allocated in mmapped regions (bytes)
  87. Info.hblkhd = Stats[scudo::StatMapped];
  88. // Maximum total allocated space (bytes)
  89. Info.usmblks = Info.hblkhd;
  90. // Space in freed fastbin blocks (bytes)
  91. Info.fsmblks = Stats[scudo::StatFree];
  92. // Total allocated space (bytes)
  93. Info.uordblks = Stats[scudo::StatAllocated];
  94. // Total free space (bytes)
  95. Info.fordblks = Info.fsmblks;
  96. return Info;
  97. }
  98. #endif
  99. INTERFACE WEAK void *SCUDO_PREFIX(malloc)(size_t size) {
  100. void *Ptr = SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Malloc,
  101. SCUDO_MALLOC_ALIGNMENT);
  102. reportAllocation(Ptr, size);
  103. return scudo::setErrnoOnNull(Ptr);
  104. }
  105. #if SCUDO_ANDROID
  106. INTERFACE WEAK size_t SCUDO_PREFIX(malloc_usable_size)(const void *ptr) {
  107. #else
  108. INTERFACE WEAK size_t SCUDO_PREFIX(malloc_usable_size)(void *ptr) {
  109. #endif
  110. return SCUDO_ALLOCATOR.getUsableSize(ptr);
  111. }
  112. INTERFACE WEAK void *SCUDO_PREFIX(memalign)(size_t alignment, size_t size) {
  113. // Android rounds up the alignment to a power of two if it isn't one.
  114. if (SCUDO_ANDROID) {
  115. if (UNLIKELY(!alignment)) {
  116. alignment = 1U;
  117. } else {
  118. if (UNLIKELY(!scudo::isPowerOfTwo(alignment)))
  119. alignment = scudo::roundUpPowerOfTwo(alignment);
  120. }
  121. } else {
  122. if (UNLIKELY(!scudo::isPowerOfTwo(alignment))) {
  123. if (SCUDO_ALLOCATOR.canReturnNull()) {
  124. errno = EINVAL;
  125. return nullptr;
  126. }
  127. scudo::reportAlignmentNotPowerOfTwo(alignment);
  128. }
  129. }
  130. void *Ptr =
  131. SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Memalign, alignment);
  132. reportAllocation(Ptr, size);
  133. return Ptr;
  134. }
  135. INTERFACE WEAK int SCUDO_PREFIX(posix_memalign)(void **memptr, size_t alignment,
  136. size_t size) {
  137. if (UNLIKELY(scudo::checkPosixMemalignAlignment(alignment))) {
  138. if (!SCUDO_ALLOCATOR.canReturnNull())
  139. scudo::reportInvalidPosixMemalignAlignment(alignment);
  140. return EINVAL;
  141. }
  142. void *Ptr =
  143. SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Memalign, alignment);
  144. if (UNLIKELY(!Ptr))
  145. return ENOMEM;
  146. reportAllocation(Ptr, size);
  147. *memptr = Ptr;
  148. return 0;
  149. }
  150. INTERFACE WEAK void *SCUDO_PREFIX(pvalloc)(size_t size) {
  151. const scudo::uptr PageSize = scudo::getPageSizeCached();
  152. if (UNLIKELY(scudo::checkForPvallocOverflow(size, PageSize))) {
  153. if (SCUDO_ALLOCATOR.canReturnNull()) {
  154. errno = ENOMEM;
  155. return nullptr;
  156. }
  157. scudo::reportPvallocOverflow(size);
  158. }
  159. // pvalloc(0) should allocate one page.
  160. void *Ptr =
  161. SCUDO_ALLOCATOR.allocate(size ? scudo::roundUp(size, PageSize) : PageSize,
  162. scudo::Chunk::Origin::Memalign, PageSize);
  163. reportAllocation(Ptr, scudo::roundUp(size, PageSize));
  164. return scudo::setErrnoOnNull(Ptr);
  165. }
  166. INTERFACE WEAK void *SCUDO_PREFIX(realloc)(void *ptr, size_t size) {
  167. if (!ptr) {
  168. void *Ptr = SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Malloc,
  169. SCUDO_MALLOC_ALIGNMENT);
  170. reportAllocation(Ptr, size);
  171. return scudo::setErrnoOnNull(Ptr);
  172. }
  173. if (size == 0) {
  174. reportDeallocation(ptr);
  175. SCUDO_ALLOCATOR.deallocate(ptr, scudo::Chunk::Origin::Malloc);
  176. return nullptr;
  177. }
  178. // Given that the reporting of deallocation and allocation are not atomic, we
  179. // always pretend the old pointer will be released so that the user doesn't
  180. // need to worry about the false double-use case from the view of hooks.
  181. //
  182. // For example, assume that `realloc` releases the old pointer and allocates a
  183. // new pointer. Before the reporting of both operations has been done, another
  184. // thread may get the old pointer from `malloc`. It may be misinterpreted as
  185. // double-use if it's not handled properly on the hook side.
  186. reportReallocDeallocation(ptr);
  187. void *NewPtr = SCUDO_ALLOCATOR.reallocate(ptr, size, SCUDO_MALLOC_ALIGNMENT);
  188. if (NewPtr != nullptr) {
  189. // Note that even if NewPtr == ptr, the size has changed. We still need to
  190. // report the new size.
  191. reportReallocAllocation(/*OldPtr=*/ptr, NewPtr, size);
  192. } else {
  193. // If `realloc` fails, the old pointer is not released. Report the old
  194. // pointer as allocated again.
  195. reportReallocAllocation(/*OldPtr=*/ptr, /*NewPtr=*/ptr,
  196. SCUDO_ALLOCATOR.getAllocSize(ptr));
  197. }
  198. return scudo::setErrnoOnNull(NewPtr);
  199. }
  200. INTERFACE WEAK void *SCUDO_PREFIX(valloc)(size_t size) {
  201. void *Ptr = SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Memalign,
  202. scudo::getPageSizeCached());
  203. reportAllocation(Ptr, size);
  204. return scudo::setErrnoOnNull(Ptr);
  205. }
  206. INTERFACE WEAK int SCUDO_PREFIX(malloc_iterate)(
  207. uintptr_t base, size_t size,
  208. void (*callback)(uintptr_t base, size_t size, void *arg), void *arg) {
  209. SCUDO_ALLOCATOR.iterateOverChunks(base, size, callback, arg);
  210. return 0;
  211. }
  212. INTERFACE WEAK void SCUDO_PREFIX(malloc_enable)() { SCUDO_ALLOCATOR.enable(); }
  213. INTERFACE WEAK void SCUDO_PREFIX(malloc_disable)() {
  214. SCUDO_ALLOCATOR.disable();
  215. }
  216. void SCUDO_PREFIX(malloc_postinit)() {
  217. SCUDO_ALLOCATOR.initGwpAsan();
  218. pthread_atfork(SCUDO_PREFIX(malloc_disable), SCUDO_PREFIX(malloc_enable),
  219. SCUDO_PREFIX(malloc_enable));
  220. }
  221. INTERFACE WEAK int SCUDO_PREFIX(mallopt)(int param, int value) {
  222. if (param == M_DECAY_TIME) {
  223. if (SCUDO_ANDROID) {
  224. if (value == 0) {
  225. // Will set the release values to their minimum values.
  226. value = INT32_MIN;
  227. } else {
  228. // Will set the release values to their maximum values.
  229. value = INT32_MAX;
  230. }
  231. }
  232. SCUDO_ALLOCATOR.setOption(scudo::Option::ReleaseInterval,
  233. static_cast<scudo::sptr>(value));
  234. return 1;
  235. } else if (param == M_PURGE) {
  236. SCUDO_ALLOCATOR.releaseToOS(scudo::ReleaseToOS::Force);
  237. return 1;
  238. } else if (param == M_PURGE_ALL) {
  239. SCUDO_ALLOCATOR.releaseToOS(scudo::ReleaseToOS::ForceAll);
  240. return 1;
  241. } else if (param == M_LOG_STATS) {
  242. SCUDO_ALLOCATOR.printStats();
  243. SCUDO_ALLOCATOR.printFragmentationInfo();
  244. return 1;
  245. } else {
  246. scudo::Option option;
  247. switch (param) {
  248. case M_MEMTAG_TUNING:
  249. option = scudo::Option::MemtagTuning;
  250. break;
  251. case M_THREAD_DISABLE_MEM_INIT:
  252. option = scudo::Option::ThreadDisableMemInit;
  253. break;
  254. case M_CACHE_COUNT_MAX:
  255. option = scudo::Option::MaxCacheEntriesCount;
  256. break;
  257. case M_CACHE_SIZE_MAX:
  258. option = scudo::Option::MaxCacheEntrySize;
  259. break;
  260. case M_TSDS_COUNT_MAX:
  261. option = scudo::Option::MaxTSDsCount;
  262. break;
  263. default:
  264. return 0;
  265. }
  266. return SCUDO_ALLOCATOR.setOption(option, static_cast<scudo::sptr>(value));
  267. }
  268. }
  269. INTERFACE WEAK void *SCUDO_PREFIX(aligned_alloc)(size_t alignment,
  270. size_t size) {
  271. if (UNLIKELY(scudo::checkAlignedAllocAlignmentAndSize(alignment, size))) {
  272. if (SCUDO_ALLOCATOR.canReturnNull()) {
  273. errno = EINVAL;
  274. return nullptr;
  275. }
  276. scudo::reportInvalidAlignedAllocAlignment(alignment, size);
  277. }
  278. void *Ptr =
  279. SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Malloc, alignment);
  280. reportAllocation(Ptr, size);
  281. return scudo::setErrnoOnNull(Ptr);
  282. }
  283. INTERFACE WEAK int SCUDO_PREFIX(malloc_info)(UNUSED int options, FILE *stream) {
  284. const scudo::uptr max_size =
  285. decltype(SCUDO_ALLOCATOR)::PrimaryT::SizeClassMap::MaxSize;
  286. auto *sizes = static_cast<scudo::uptr *>(
  287. SCUDO_PREFIX(calloc)(max_size, sizeof(scudo::uptr)));
  288. auto callback = [](uintptr_t, size_t size, void *arg) {
  289. auto *sizes = reinterpret_cast<scudo::uptr *>(arg);
  290. if (size < max_size)
  291. sizes[size]++;
  292. };
  293. SCUDO_ALLOCATOR.disable();
  294. SCUDO_ALLOCATOR.iterateOverChunks(0, -1ul, callback, sizes);
  295. SCUDO_ALLOCATOR.enable();
  296. fputs("<malloc version=\"scudo-1\">\n", stream);
  297. for (scudo::uptr i = 0; i != max_size; ++i)
  298. if (sizes[i])
  299. fprintf(stream, "<alloc size=\"%zu\" count=\"%zu\"/>\n", i, sizes[i]);
  300. fputs("</malloc>\n", stream);
  301. SCUDO_PREFIX(free)(sizes);
  302. return 0;
  303. }
  304. // Disable memory tagging for the heap. The caller must disable memory tag
  305. // checks globally (e.g. by clearing TCF0 on aarch64) before calling this
  306. // function, and may not re-enable them after calling the function.
  307. INTERFACE WEAK void SCUDO_PREFIX(malloc_disable_memory_tagging)() {
  308. SCUDO_ALLOCATOR.disableMemoryTagging();
  309. }
  310. // Sets whether scudo records stack traces and other metadata for allocations
  311. // and deallocations. This function only has an effect if the allocator and
  312. // hardware support memory tagging.
  313. INTERFACE WEAK void
  314. SCUDO_PREFIX(malloc_set_track_allocation_stacks)(int track) {
  315. SCUDO_ALLOCATOR.setTrackAllocationStacks(track);
  316. }
  317. // Sets whether scudo zero-initializes all allocated memory.
  318. INTERFACE WEAK void SCUDO_PREFIX(malloc_set_zero_contents)(int zero_contents) {
  319. SCUDO_ALLOCATOR.setFillContents(zero_contents ? scudo::ZeroFill
  320. : scudo::NoFill);
  321. }
  322. // Sets whether scudo pattern-initializes all allocated memory.
  323. INTERFACE WEAK void
  324. SCUDO_PREFIX(malloc_set_pattern_fill_contents)(int pattern_fill_contents) {
  325. SCUDO_ALLOCATOR.setFillContents(
  326. pattern_fill_contents ? scudo::PatternOrZeroFill : scudo::NoFill);
  327. }
  328. // Sets whether scudo adds a small amount of slack at the end of large
  329. // allocations, before the guard page. This can be enabled to work around buggy
  330. // applications that read a few bytes past the end of their allocation.
  331. INTERFACE WEAK void
  332. SCUDO_PREFIX(malloc_set_add_large_allocation_slack)(int add_slack) {
  333. SCUDO_ALLOCATOR.setAddLargeAllocationSlack(add_slack);
  334. }
  335. } // extern "C"