diff options
author | Alexander Smirnov <alex@ydb.tech> | 2025-03-06 00:51:48 +0000 |
---|---|---|
committer | Alexander Smirnov <alex@ydb.tech> | 2025-03-06 00:51:48 +0000 |
commit | e820fdf8153ad722cf88953b2c13b70daf4918bd (patch) | |
tree | 4f4a9bc60753762496960c846821cc01270666d0 /library/cpp | |
parent | f401330bcd39c4d294727fd88b8b912c7cb74115 (diff) | |
parent | 16867b871a3abf548c504976fb8ca49c882b1ffd (diff) | |
download | ydb-e820fdf8153ad722cf88953b2c13b70daf4918bd.tar.gz |
Merge branch 'rightlib' into merge-libs-250306-0050
Diffstat (limited to 'library/cpp')
-rw-r--r-- | library/cpp/containers/compact_vector/compact_vector.h | 24 | ||||
-rw-r--r-- | library/cpp/containers/compact_vector/compact_vector_ut.cpp | 35 | ||||
-rw-r--r-- | library/cpp/yt/memory/poison-inl.h | 24 | ||||
-rw-r--r-- | library/cpp/yt/memory/poison.cpp | 46 | ||||
-rw-r--r-- | library/cpp/yt/memory/poison.h | 35 | ||||
-rw-r--r-- | library/cpp/yt/misc/property.h | 13 |
6 files changed, 131 insertions, 46 deletions
diff --git a/library/cpp/containers/compact_vector/compact_vector.h b/library/cpp/containers/compact_vector/compact_vector.h index 984ec6ac00d..cff5345ee22 100644 --- a/library/cpp/containers/compact_vector/compact_vector.h +++ b/library/cpp/containers/compact_vector/compact_vector.h @@ -113,6 +113,14 @@ public: return *this; } + bool operator==(const TCompactVector<T>& other) const { + return size() == other.size() && std::equal(begin(), end(), other.begin()); + } + + explicit operator bool() const { + return !empty(); + } + TIterator Begin() { return Ptr; } @@ -218,15 +226,25 @@ public: } void PushBack(const T& elem) { - Reserve(Size() + 1); - new (Ptr + Size()) T(elem); - ++(Header()->Size); + EmplaceBack(elem); } void push_back(const T& elem) { PushBack(elem); } + template <class... Args> + void EmplaceBack(Args&&... args) { + Reserve(Size() + 1); + new (Ptr + Size()) T(std::forward<Args>(args)...); + ++(Header()->Size); + } + + template <class... Args> + void emplace_back(Args&&... args) { + EmplaceBack(std::forward<Args>(args)...); + } + T& Back() { return *(End() - 1); } diff --git a/library/cpp/containers/compact_vector/compact_vector_ut.cpp b/library/cpp/containers/compact_vector/compact_vector_ut.cpp index 4dba7b2f49e..5aac5303f32 100644 --- a/library/cpp/containers/compact_vector/compact_vector_ut.cpp +++ b/library/cpp/containers/compact_vector/compact_vector_ut.cpp @@ -2,6 +2,8 @@ #include "compact_vector.h" +#include <string> + Y_UNIT_TEST_SUITE(TCompactVectorTest) { Y_UNIT_TEST(TestSimple1) { } @@ -44,6 +46,28 @@ Y_UNIT_TEST_SUITE(TCompactVectorTest) { UNIT_ASSERT_VALUES_EQUAL(11u, vector[11]); } + Y_UNIT_TEST(TestEmplace) { + struct TFoo { + explicit TFoo(int) + : ConstructedFrom("int") + { + } + + explicit TFoo(char) + : ConstructedFrom("char") + { + } + + std::string ConstructedFrom; + }; + + TCompactVector<TFoo> vector; + vector.emplace_back(123); + UNIT_ASSERT_VALUES_EQUAL(vector.back().ConstructedFrom, "int"); + vector.emplace_back('c'); + UNIT_ASSERT_VALUES_EQUAL(vector.back().ConstructedFrom, "char"); + } + Y_UNIT_TEST(TestInitializerListConstructor) { TCompactVector<ui32> vector = { 4, 8, 10, 3, 5}; UNIT_ASSERT_VALUES_EQUAL(5u, vector.Size()); @@ -146,4 +170,15 @@ Y_UNIT_TEST_SUITE(TCompactVectorTest) { UNIT_ASSERT_VALUES_EQUAL(vector[1], vector2[1]); UNIT_ASSERT_VALUES_EQUAL(vector[2], vector2[2]); } + + Y_UNIT_TEST(TestComparison) { + // UNIT_ASSERT_VALUES_EQUAL needs a specialization for Out(), so we just use bool assertions + TCompactVector<int> vector {1, 2, 3}; + TCompactVector<int> vector2 {1, 2}; + UNIT_ASSERT(vector != vector2); // diff size + vector2.emplace_back(4); + UNIT_ASSERT(vector != vector2); // diff values + vector2.back() = 3; + UNIT_ASSERT(vector == vector2); + } } diff --git a/library/cpp/yt/memory/poison-inl.h b/library/cpp/yt/memory/poison-inl.h index c7563565a89..1625de04847 100644 --- a/library/cpp/yt/memory/poison-inl.h +++ b/library/cpp/yt/memory/poison-inl.h @@ -18,12 +18,15 @@ void __asan_poison_memory_region(void const volatile *addr, size_t size); void __asan_unpoison_memory_region(void const volatile *addr, size_t size); } // extern "C" -Y_FORCE_INLINE void PoisonMemory(TMutableRef ref) +Y_FORCE_INLINE void PoisonUninitializedMemory(TMutableRef /*ref*/) +{ } + +Y_FORCE_INLINE void PoisonFreedMemory(TMutableRef ref) { __asan_poison_memory_region(ref.data(), ref.size()); } -Y_FORCE_INLINE void UnpoisonMemory(TMutableRef ref) +Y_FORCE_INLINE void RecycleFreedMemory(TMutableRef ref) { __asan_unpoison_memory_region(ref.data(), ref.size()); } @@ -31,26 +34,31 @@ Y_FORCE_INLINE void UnpoisonMemory(TMutableRef ref) #elif defined(_msan_enabled_) extern "C" { -void __msan_unpoison(const volatile void* a, size_t size); void __msan_poison(const volatile void* a, size_t size); } // extern "C" -Y_FORCE_INLINE void PoisonMemory(TMutableRef ref) +Y_FORCE_INLINE void PoisonUninitializedMemory(TMutableRef ref) { __msan_poison(ref.data(), ref.size()); } -Y_FORCE_INLINE void UnpoisonMemory(TMutableRef ref) +Y_FORCE_INLINE void PoisonFreedMemory(TMutableRef ref) { - __msan_unpoison(ref.data(), ref.size()); + __msan_poison(ref.data(), ref.size()); } +Y_FORCE_INLINE void RecycleFreedMemory(TMutableRef /*ref*/) +{ } + #elif defined(NDEBUG) -Y_FORCE_INLINE void PoisonMemory(TMutableRef /*ref*/) +Y_FORCE_INLINE void PoisonUninitializedMemory(TMutableRef /*ref*/) +{ } + +Y_FORCE_INLINE void PoisonFreedMemory(TMutableRef /*ref*/) { } -Y_FORCE_INLINE void UnpoisonMemory(TMutableRef /*ref*/) +Y_FORCE_INLINE void RecycleFreedMemory(TMutableRef /*ref*/) { } #endif diff --git a/library/cpp/yt/memory/poison.cpp b/library/cpp/yt/memory/poison.cpp index bc4bcad4e02..2d05246df8f 100644 --- a/library/cpp/yt/memory/poison.cpp +++ b/library/cpp/yt/memory/poison.cpp @@ -6,57 +6,51 @@ namespace NYT { namespace { -template <char Byte0, char Byte1, char Byte2, char Byte3, char Byte4, char Byte5, char Byte6, char Byte7> +template <char Byte0, char Byte1, char Byte2, char Byte3> void ClobberMemory(char* __restrict__ ptr, size_t size) { - while (size >= 8) { + while (size >= 4) { *ptr++ = Byte0; *ptr++ = Byte1; *ptr++ = Byte2; *ptr++ = Byte3; - *ptr++ = Byte4; - *ptr++ = Byte5; - *ptr++ = Byte6; - *ptr++ = Byte7; - size -= 8; + size -= 4; } switch (size) { - case 7: - *ptr++ = Byte0; - [[fallthrough]]; - case 6: - *ptr++ = Byte1; - [[fallthrough]]; - case 5: - *ptr++ = Byte2; - [[fallthrough]]; - case 4: - *ptr++ = Byte3; - [[fallthrough]]; case 3: - *ptr++ = Byte4; + *ptr++ = Byte0; [[fallthrough]]; case 2: - *ptr++ = Byte5; + *ptr++ = Byte1; [[fallthrough]]; case 1: - *ptr++ = Byte6; + *ptr++ = Byte2; } } } // namespace #if !defined(NDEBUG) && !defined(_asan_enabled_) && !defined(_msan_enabled_) -void PoisonMemory(TMutableRef ref) + +void PoisonUninitializedMemory(TMutableRef ref) { - ClobberMemory<'d', 'e', 'a', 'd', 'b', 'e', 'e', 'f'>(ref.data(), ref.size()); + // BAADBOBA + ClobberMemory<'\xba', '\xad', '\xb0', '\xba'>(ref.data(), ref.size()); } -void UnpoisonMemory(TMutableRef ref) +void PoisonFreedMemory(TMutableRef ref) { - ClobberMemory<'c', 'a', 'f', 'e', 'b', 'a', 'b', 'e'>(ref.data(), ref.size()); + // DEADBEEF + ClobberMemory<'\xde', '\xad', '\xbe', '\xef'>(ref.data(), ref.size()); } + +void RecycleFreedMemory(TMutableRef ref) +{ + // COOLBIBA + ClobberMemory<'\xc0', '\x01', '\xb1', '\xba'>(ref.data(), ref.size()); +} + #endif //////////////////////////////////////////////////////////////////////////////// diff --git a/library/cpp/yt/memory/poison.h b/library/cpp/yt/memory/poison.h index 9519f3da10e..cdd7eb557a0 100644 --- a/library/cpp/yt/memory/poison.h +++ b/library/cpp/yt/memory/poison.h @@ -6,15 +6,32 @@ namespace NYT { //////////////////////////////////////////////////////////////////////////////// -//! In release builds, does nothing. -//! In checked builds, clobbers memory with garbage pattern. -//! In sanitized builds, invokes sanitizer poisoning. -void PoisonMemory(TMutableRef ref); - -//! In release builds, does nothing. -//! In checked builds, clobbers memory with (another) garbage pattern. -//! In sanitized builds, invokes sanitizer unpoisoning. -void UnpoisonMemory(TMutableRef ref); +//! Poisons an uninitialized slice of memory. +/* + * In release builds, does nothing. + * In checked builds, clobbers memory with a garbage pattern. + * In ASAN builds, does nothing. + * In MSAN builds, invokes sanitizer poisoning to catch uninit-read. + */ +void PoisonUninitializedMemory(TMutableRef ref); + +//! Poisons a freed slice of memory. +/* + * In release builds, does nothing. + * In checked builds, clobbers memory with a garbage pattern. + * In ASAN and MSAN builds, invokes sanitizer poisoning to catch use-after-free. + */ +void PoisonFreedMemory(TMutableRef ref); + +//! Indicates that a slice of memory that was previously given to #PoisonFreedMemory +//! has been recycled and can be reused. +/*! + * In release builds, does nothing. + * In checked builds, clobbers memory with a garbage pattern. + * In ASAN builds, invokes sanitizer unpoisoning. + * In MSAN builds, does nothing (the memory remains poisoned to catch uninit-read). + */ +void RecycleFreedMemory(TMutableRef ref); //////////////////////////////////////////////////////////////////////////////// diff --git a/library/cpp/yt/misc/property.h b/library/cpp/yt/misc/property.h index 3c42693ef3f..722e7cb2b8e 100644 --- a/library/cpp/yt/misc/property.h +++ b/library/cpp/yt/misc/property.h @@ -175,6 +175,19 @@ public: \ } \ static_assert(true) +//! Defines a trivial public read-only boolean property that is passed by value. +//! All arguments after name are used as default value (via braced-init-list). +#define DEFINE_BYVAL_RO_BOOLEAN_PROPERTY(name, ...) \ +protected: \ + bool name##_ { __VA_ARGS__ }; \ + \ +public: \ + Y_FORCE_INLINE bool Is##name() const \ + { \ + return name##_; \ + } \ + static_assert(true) + //! Defines a trivial public read-write property that is passed by value. //! All arguments after name are used as default value (via braced-init-list). #define DEFINE_BYVAL_RW_PROPERTY_WITH_FLUENT_SETTER(declaringType, type, name, ...) \ |