diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/balloc | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/balloc')
-rw-r--r-- | library/cpp/balloc/balloc.cpp | 308 | ||||
-rw-r--r-- | library/cpp/balloc/malloc-info.cpp | 41 | ||||
-rw-r--r-- | library/cpp/balloc/optional/operators.cpp | 1 | ||||
-rw-r--r-- | library/cpp/balloc/optional/operators.h | 16 | ||||
-rw-r--r-- | library/cpp/balloc/optional/ya.make | 15 | ||||
-rw-r--r-- | library/cpp/balloc/ya.make | 28 |
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() |