[llvm-branch-commits] [compiler-rt] [nsan] Use sanitizer allocator (PR #102764)
Fangrui Song via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sun Aug 11 13:30:23 PDT 2024
================
@@ -0,0 +1,334 @@
+//===- nsan_allocator.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// NumericalStabilitySanitizer allocator.
+//
+//===----------------------------------------------------------------------===//
+
+#include "nsan_allocator.h"
+#include "interception/interception.h"
+#include "nsan.h"
+#include "nsan_platform.h"
+#include "nsan_thread.h"
+#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_checks.h"
+#include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "sanitizer_common/sanitizer_allocator_report.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_errno.h"
+
+DECLARE_REAL(void *, memset, void *dest, int c, uptr n)
+
+using namespace __nsan;
+
+namespace {
+struct Metadata {
+ uptr requested_size;
+};
+
+struct NsanMapUnmapCallback {
+ void OnMap(uptr p, uptr size) const {}
+ void OnMapSecondary(uptr p, uptr size, uptr user_begin,
+ uptr user_size) const {}
+ void OnUnmap(uptr p, uptr size) const {}
+};
+
+const uptr kMaxAllowedMallocSize = 1ULL << 40;
+
+// Allocator64 parameters. Deliberately using a short name.
+struct AP64 {
+ static const uptr kSpaceBeg = Mapping::kHeapMemBeg;
+ static const uptr kSpaceSize = 0x40000000000; // 4T.
+ static const uptr kMetadataSize = sizeof(Metadata);
+ using SizeClassMap = DefaultSizeClassMap;
+ using MapUnmapCallback = NsanMapUnmapCallback;
+ static const uptr kFlags = 0;
+ using AddressSpaceView = LocalAddressSpaceView;
+};
+} // namespace
+
+using PrimaryAllocator = SizeClassAllocator64<AP64>;
+using Allocator = CombinedAllocator<PrimaryAllocator>;
+using AllocatorCache = Allocator::AllocatorCache;
+
+static Allocator allocator;
+static AllocatorCache fallback_allocator_cache;
+static StaticSpinMutex fallback_mutex;
+
+static uptr max_malloc_size;
+
+void __nsan::NsanAllocatorInit() {
+ SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
+ allocator.Init(common_flags()->allocator_release_to_os_interval_ms);
+ if (common_flags()->max_allocation_size_mb)
+ max_malloc_size = Min(common_flags()->max_allocation_size_mb << 20,
+ kMaxAllowedMallocSize);
+ else
+ max_malloc_size = kMaxAllowedMallocSize;
+}
+
+static AllocatorCache *GetAllocatorCache(NsanThreadLocalMallocStorage *ms) {
+ CHECK(ms);
+ CHECK_LE(sizeof(AllocatorCache), sizeof(ms->allocator_cache));
+ return reinterpret_cast<AllocatorCache *>(ms->allocator_cache);
+}
+
+void NsanThreadLocalMallocStorage::Init() {
+ allocator.InitCache(GetAllocatorCache(this));
+}
+
+void NsanThreadLocalMallocStorage::CommitBack() {
+ allocator.SwallowCache(GetAllocatorCache(this));
+ allocator.DestroyCache(GetAllocatorCache(this));
+}
+
+static void *NsanAllocate(uptr size, uptr alignment, bool zero) {
+ if (UNLIKELY(size > max_malloc_size)) {
+ if (AllocatorMayReturnNull()) {
+ Report("WARNING: NumericalStabilitySanitizer failed to allocate 0x%zx "
+ "bytes\n",
+ size);
+ return nullptr;
+ }
+ BufferedStackTrace stack;
+ GET_FATAL_STACK_TRACE_IF_EMPTY(&stack);
+ ReportAllocationSizeTooBig(size, max_malloc_size, &stack);
+ }
+ if (UNLIKELY(IsRssLimitExceeded())) {
+ if (AllocatorMayReturnNull())
+ return nullptr;
+ BufferedStackTrace stack;
+ GET_FATAL_STACK_TRACE_IF_EMPTY(&stack);
+ ReportRssLimitExceeded(&stack);
+ }
+ NsanThread *t = GetCurrentThread();
+ void *allocated;
+ if (t) {
+ AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
+ allocated = allocator.Allocate(cache, size, alignment);
+ } else {
----------------
MaskRay wrote:
I added a comment here. Say, the main thread creates a new thread. The main thread allocates TLS blocks (`nsan_current_thread == main_thread`).
In glibc, when nptl/allocatestack.c create or resize the guard area, it might call `_dl_deallocate_tls` on the TLS blocks. This happens at very early stage of pthread_create and the TLS `nsan_current_thread` is nullptr.
https://github.com/llvm/llvm-project/pull/102764
More information about the llvm-branch-commits
mailing list