aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp
diff options
context:
space:
mode:
authorAlexander Smirnov <alex@ydb.tech>2025-03-06 00:51:48 +0000
committerAlexander Smirnov <alex@ydb.tech>2025-03-06 00:51:48 +0000
commite820fdf8153ad722cf88953b2c13b70daf4918bd (patch)
tree4f4a9bc60753762496960c846821cc01270666d0 /library/cpp
parentf401330bcd39c4d294727fd88b8b912c7cb74115 (diff)
parent16867b871a3abf548c504976fb8ca49c882b1ffd (diff)
downloadydb-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.h24
-rw-r--r--library/cpp/containers/compact_vector/compact_vector_ut.cpp35
-rw-r--r--library/cpp/yt/memory/poison-inl.h24
-rw-r--r--library/cpp/yt/memory/poison.cpp46
-rw-r--r--library/cpp/yt/memory/poison.h35
-rw-r--r--library/cpp/yt/misc/property.h13
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, ...) \