aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/balloc
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/balloc
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/balloc')
-rw-r--r--library/cpp/balloc/balloc.cpp308
-rw-r--r--library/cpp/balloc/malloc-info.cpp41
-rw-r--r--library/cpp/balloc/optional/operators.cpp1
-rw-r--r--library/cpp/balloc/optional/operators.h16
-rw-r--r--library/cpp/balloc/optional/ya.make15
-rw-r--r--library/cpp/balloc/ya.make28
6 files changed, 409 insertions, 0 deletions
diff --git a/library/cpp/balloc/balloc.cpp b/library/cpp/balloc/balloc.cpp
new file mode 100644
index 0000000000..fab489db4c
--- /dev/null
+++ b/library/cpp/balloc/balloc.cpp
@@ -0,0 +1,308 @@
+#include <library/cpp/balloc/lib/balloc.h>
+#include <errno.h>
+
+namespace NBalloc {
+
+ static constexpr size_t ALIVE_SIGNATURE = 0xaULL << 56;
+ static constexpr size_t DISABLED_SIGNATURE = 0xbULL << 56;
+ static constexpr size_t SIGNATURE_MASK = 0xfULL << 56;
+
+ static constexpr size_t MINIMAL_ALIGNMENT = sizeof(NBalloc::TAllocHeader);
+ static_assert(((MINIMAL_ALIGNMENT - 1) & MINIMAL_ALIGNMENT) == 0,
+ "invalid BALLOC_MINIMAL_ALIGNMENT");
+
+ static Y_FORCE_INLINE void* Malloc(size_t size) {
+ TLS& ltls = tls;
+ size = Align(size, sizeof(TAllocHeader));
+ if (Y_UNLIKELY(ltls.Mode == Empty || ltls.Mode == ToBeEnabled)) {
+ Init(ltls);
+ }
+ if (Y_LIKELY(ltls.Mode != Disabled)) {
+ TAllocHeader* allocHeader = AllocateRaw(size, ALIVE_SIGNATURE);
+ return allocHeader + 1;
+ } else {
+ // ltls.Mode == Disabled
+ const size_t extsize = size + sizeof(TAllocHeader);
+ TAllocHeader* allocHeader = (TAllocHeader*)LibcMalloc(extsize);
+ allocHeader->Encode(allocHeader, size, DISABLED_SIGNATURE);
+ return allocHeader + 1;
+ }
+ }
+
+ static void Y_FORCE_INLINE Free(void* ptr) {
+ if (ptr == nullptr) {
+ return;
+ }
+ TAllocHeader* allocHeader = ((TAllocHeader*)ptr) - 1;
+ size_t size = allocHeader->AllocSize;
+ const size_t signature = size & SIGNATURE_MASK;
+ if (Y_LIKELY(signature == ALIVE_SIGNATURE)) {
+ allocHeader->AllocSize = 0; // abort later on double free
+#ifdef DBG_FILL_MEMORY
+ memset(ptr, 0xde, size - signature);
+#endif
+ FreeRaw(allocHeader->Block);
+ if (NAllocStats::IsEnabled()) {
+ NAllocStats::DecThreadAllocStats(size - signature);
+ }
+ } else if (signature == DISABLED_SIGNATURE) {
+ LibcFree(allocHeader->Block);
+ } else {
+ NMalloc::AbortFromCorruptedAllocator();
+ }
+ }
+
+ static bool Y_FORCE_INLINE IsOwnedByBalloc(void* ptr) {
+ TAllocHeader* allocHeader = ((TAllocHeader*)ptr) - 1;
+ size_t size = allocHeader->AllocSize;
+ const size_t signature = size & SIGNATURE_MASK;
+ if (signature == ALIVE_SIGNATURE) {
+ return true;
+ } else if (signature == DISABLED_SIGNATURE) {
+ return false;
+ }
+ NMalloc::AbortFromCorruptedAllocator();
+ Y_UNREACHABLE();
+ }
+
+ static void Y_FORCE_INLINE Disable() {
+#if defined(_musl_)
+ // just skip it
+#else
+ tls.Mode = Disabled;
+#endif
+ }
+
+ static void Y_FORCE_INLINE Enable() {
+ tls.Mode = ToBeEnabled;
+ }
+
+ static bool Y_FORCE_INLINE IsDisabled() {
+ return tls.Mode == Disabled;
+ }
+};
+
+#if defined(Y_COVER_PTR)
+void* CoverPtr(void* ptr, size_t len) noexcept;
+void* UncoverPtr(void* ptr) noexcept;
+#endif
+
+extern "C" void* malloc(size_t size) {
+#if defined(Y_COVER_PTR)
+ return CoverPtr(NBalloc::Malloc(size + 32), size);
+#else
+ return NBalloc::Malloc(size);
+#endif
+}
+
+extern "C" void free(void* data) {
+#if defined(Y_COVER_PTR)
+ NBalloc::Free(UncoverPtr(data));
+#else
+ NBalloc::Free(data);
+#endif
+}
+
+#if defined(USE_INTELCC) || defined(_darwin_) || defined(_freebsd_) || defined(_STLPORT_VERSION)
+#define OP_THROWNOTHING noexcept
+#else
+#define OP_THROWNOTHING
+#endif
+
+void* operator new(size_t size) {
+#if defined(Y_COVER_PTR)
+ return malloc(size);
+#else
+ return NBalloc::Malloc(size);
+#endif
+}
+
+int posix_memalign(void** memptr, const size_t alignment, const size_t size) {
+#if defined(Y_COVER_PTR)
+ (void)alignment;
+ *memptr = malloc(size);
+ return 0;
+#else
+ if (((alignment - 1) & alignment) != 0 || alignment < sizeof(void*)) {
+ return EINVAL;
+ }
+ if (alignment <= NBalloc::MINIMAL_ALIGNMENT) {
+ *memptr = NBalloc::Malloc(size);
+ return 0;
+ }
+ size_t bigSize = size + alignment - NBalloc::MINIMAL_ALIGNMENT;
+ void* res = NBalloc::Malloc(bigSize);
+ void* alignedPtr = (void*)NBalloc::Align((size_t)res, alignment);
+ if (alignedPtr != res) {
+ auto oldAllocHeader = (NBalloc::TAllocHeader*)res - 1;
+ auto newAllocHeader = (NBalloc::TAllocHeader*)alignedPtr - 1;
+ void* block = oldAllocHeader->Block;
+ newAllocHeader->Encode(block, size, NBalloc::ALIVE_SIGNATURE);
+ }
+ *memptr = alignedPtr;
+ return 0;
+#endif
+}
+
+void* operator new(size_t size, const std::nothrow_t&) OP_THROWNOTHING {
+#if defined(Y_COVER_PTR)
+ return malloc(size);
+#else
+ return NBalloc::Malloc(size);
+#endif
+}
+
+void operator delete(void* p)OP_THROWNOTHING {
+#if defined(Y_COVER_PTR)
+ free(p);
+#else
+ NBalloc::Free(p);
+#endif
+}
+
+void operator delete(void* p, const std::nothrow_t&)OP_THROWNOTHING {
+#if defined(Y_COVER_PTR)
+ free(p);
+#else
+ NBalloc::Free(p);
+#endif
+}
+
+void* operator new[](size_t size) {
+#if defined(Y_COVER_PTR)
+ return malloc(size);
+#else
+ return NBalloc::Malloc(size);
+#endif
+}
+
+void* operator new[](size_t size, const std::nothrow_t&) OP_THROWNOTHING {
+#if defined(Y_COVER_PTR)
+ return malloc(size);
+#else
+ return NBalloc::Malloc(size);
+#endif
+}
+
+void operator delete[](void* p) OP_THROWNOTHING {
+#if defined(Y_COVER_PTR)
+ free(p);
+#else
+ NBalloc::Free(p);
+#endif
+}
+
+void operator delete[](void* p, const std::nothrow_t&) OP_THROWNOTHING {
+#if defined(Y_COVER_PTR)
+ free(p);
+#else
+ NBalloc::Free(p);
+#endif
+}
+
+extern "C" void* calloc(size_t n, size_t elemSize) {
+ const size_t size = n * elemSize;
+
+ if (elemSize != 0 && size / elemSize != n) {
+ return nullptr;
+ }
+
+#if defined(Y_COVER_PTR)
+ void* result = malloc(size);
+#else
+ void* result = NBalloc::Malloc(size);
+#endif
+
+ if (result) {
+ memset(result, 0, size);
+ }
+
+ return result;
+}
+
+extern "C" void cfree(void* ptr) {
+#if defined(Y_COVER_PTR)
+ free(ptr);
+#else
+ NBalloc::Free(ptr);
+#endif
+}
+
+#if defined(Y_COVER_PTR)
+static inline void* DoRealloc(void* oldPtr, size_t newSize) {
+#else
+extern "C" void* realloc(void* oldPtr, size_t newSize) {
+#endif
+ if (!oldPtr) {
+ void* result = NBalloc::Malloc(newSize);
+ return result;
+ }
+ if (newSize == 0) {
+ NBalloc::Free(oldPtr);
+ return nullptr;
+ }
+ void* newPtr = NBalloc::Malloc(newSize);
+ if (!newPtr) {
+ return nullptr;
+ }
+ NBalloc::TAllocHeader* header = (NBalloc::TAllocHeader*)oldPtr - 1;
+ const size_t oldSize = header->AllocSize & ~NBalloc::SIGNATURE_MASK;
+ const size_t signature = header->AllocSize & NBalloc::SIGNATURE_MASK;
+ if (Y_LIKELY((signature == NBalloc::ALIVE_SIGNATURE) || (signature == NBalloc::DISABLED_SIGNATURE))) {
+ memcpy(newPtr, oldPtr, oldSize < newSize ? oldSize : newSize);
+ NBalloc::Free(oldPtr);
+ return newPtr;
+ }
+ NMalloc::AbortFromCorruptedAllocator();
+ return nullptr;
+}
+
+#if defined(Y_COVER_PTR)
+extern "C" void* realloc(void* oldPtr, size_t newSize) {
+ if (!oldPtr) {
+ return malloc(newSize);
+ }
+
+ if (!newSize) {
+ free(oldPtr);
+
+ return nullptr;
+ }
+
+ return CoverPtr(DoRealloc(UncoverPtr(oldPtr), newSize + 32), newSize);
+}
+#endif
+
+// Only for testing purposes. Never use in production.
+extern "C" bool IsOwnedByBalloc(void* ptr) {
+ return NBalloc::IsOwnedByBalloc(ptr);
+}
+
+extern "C" bool BallocDisabled() {
+ return NBalloc::IsDisabled();
+}
+
+extern "C" void DisableBalloc() {
+ NBalloc::Disable();
+}
+
+extern "C" void EnableBalloc() {
+ NBalloc::Enable();
+}
+
+extern "C" void* memalign(size_t alignment, size_t size) {
+ void* ptr;
+ int res = posix_memalign(&ptr, alignment, size);
+ return res ? nullptr : ptr;
+}
+
+extern "C" void* valloc(size_t size) {
+ return memalign(NBalloc::PAGE_ELEM, size);
+}
+
+#if !defined(_MSC_VER) && !defined(_freebsd_)
+// Workaround for pthread_create bug in linux.
+extern "C" void* __libc_memalign(size_t alignment, size_t size) {
+ return memalign(alignment, size);
+}
+#endif
diff --git a/library/cpp/balloc/malloc-info.cpp b/library/cpp/balloc/malloc-info.cpp
new file mode 100644
index 0000000000..604b1fb145
--- /dev/null
+++ b/library/cpp/balloc/malloc-info.cpp
@@ -0,0 +1,41 @@
+#include <library/cpp/malloc/api/malloc.h>
+
+#include <string.h>
+
+using namespace NMalloc;
+
+extern "C" void DisableBalloc();
+extern "C" void EnableBalloc();
+extern "C" bool BallocDisabled();
+
+namespace {
+ bool SetAllocParam(const char* name, const char* value) {
+ if (strcmp(name, "disable") == 0) {
+ if (value == nullptr || strcmp(value, "false") != 0) {
+ // all values other than "false" are considred to be "true" for compatibility
+ DisableBalloc();
+ } else {
+ EnableBalloc();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ bool CheckAllocParam(const char* name, bool defaultValue) {
+ if (strcmp(name, "disable") == 0) {
+ return BallocDisabled();
+ }
+ return defaultValue;
+ }
+}
+
+TMallocInfo NMalloc::MallocInfo() {
+ TMallocInfo r;
+
+ r.Name = "balloc";
+ r.SetParam = SetAllocParam;
+ r.CheckParam = CheckAllocParam;
+
+ return r;
+}
diff --git a/library/cpp/balloc/optional/operators.cpp b/library/cpp/balloc/optional/operators.cpp
new file mode 100644
index 0000000000..79f74a5806
--- /dev/null
+++ b/library/cpp/balloc/optional/operators.cpp
@@ -0,0 +1 @@
+#include "operators.h"
diff --git a/library/cpp/balloc/optional/operators.h b/library/cpp/balloc/optional/operators.h
new file mode 100644
index 0000000000..6107d28a6e
--- /dev/null
+++ b/library/cpp/balloc/optional/operators.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <library/cpp/malloc/api/malloc.h>
+#include <util/string/type.h>
+
+inline bool BallocEnabled() {
+ return !::NMalloc::MallocInfo().CheckParam("disable", true);
+}
+
+inline void ThreadDisableBalloc() {
+ ::NMalloc::MallocInfo().SetParam("disable", "true");
+}
+
+inline void ThreadEnableBalloc() {
+ ::NMalloc::MallocInfo().SetParam("disable", "false");
+}
diff --git a/library/cpp/balloc/optional/ya.make b/library/cpp/balloc/optional/ya.make
new file mode 100644
index 0000000000..f740fc0b7d
--- /dev/null
+++ b/library/cpp/balloc/optional/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(ivanmorozov)
+
+SRCS(
+ operators.cpp
+)
+
+PEERDIR(
+ library/cpp/malloc/api
+)
+
+END()
+
+NEED_CHECK()
diff --git a/library/cpp/balloc/ya.make b/library/cpp/balloc/ya.make
new file mode 100644
index 0000000000..d4457fbba9
--- /dev/null
+++ b/library/cpp/balloc/ya.make
@@ -0,0 +1,28 @@
+LIBRARY()
+
+OWNER(
+ ironpeter
+ g:base
+)
+
+NO_UTIL()
+NO_COMPILER_WARNINGS()
+
+IF (OS_WINDOWS)
+ PEERDIR(
+ library/cpp/lfalloc
+ )
+ELSE()
+ SRCS(
+ balloc.cpp
+ malloc-info.cpp
+ )
+
+ PEERDIR(
+ library/cpp/balloc/lib
+ )
+ENDIF()
+
+END()
+
+NEED_CHECK()