llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lldb Author: Raphael Isemann (Teemperor) <details> <summary>Changes</summary> Use Guarded to make sure m_vtable_info_map cannot be accesses without locking the respective lock. --- Full diff: https://github.com/llvm/llvm-project/pull/219428.diff 4 Files Affected: - (modified) lldb/include/lldb/Utility/Locked.h (+28) - (modified) lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp (+4-5) - (modified) lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h (+3-2) - (modified) lldb/unittests/Utility/LockedTest.cpp (+37) ``````````diff diff --git a/lldb/include/lldb/Utility/Locked.h b/lldb/include/lldb/Utility/Locked.h index acd34e454a918..f5d7b1aa8e4d9 100644 --- a/lldb/include/lldb/Utility/Locked.h +++ b/lldb/include/lldb/Utility/Locked.h @@ -168,6 +168,34 @@ template <typename T, typename Mutex = llvm::sys::RWMutex> using SharedLockedUP = SharedLocked<std::unique_ptr<const T>, Mutex>; /// @} +/// Bundles a value of type `T` with the `Mutex` that guards it. +/// +/// This class prevents accidential use of a value without aquiring the +/// lock and should be preferred over a member + mutex pair. +/// +/// `Mutex` must satisfy `Lockable` when calling `Lock()` and `SharedLockable` +/// when calling `LockShared()`. +template <typename T, typename Mutex = llvm::sys::RWMutex> class Guarded { +public: + Guarded() = default; + explicit Guarded(T value) : m_value(std::move(value)) {} + + Guarded(const Guarded &) = delete; + Guarded &operator=(const Guarded &) = delete; + + /// Exclusive (read/write) access to the value. + Locked<T *, Mutex> Lock() { return Locked<T *, Mutex>(m_mutex, &m_value); } + + /// Shared (read-only) access to the value. + SharedLocked<const T *, Mutex> LockShared() const { + return SharedLocked<const T *, Mutex>(m_mutex, &m_value); + } + +private: + mutable Mutex m_mutex; + T m_value{}; +}; + } // namespace lldb_private #endif // LLDB_UTILITY_LOCKED_H diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index e562266e80d23..27aa2ce07a374 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -806,9 +806,9 @@ CPPLanguageRuntime::GetVTableInfoEntry(ValueObject &in_value, bool check_type) { // Check our cache first to see if we already have this info { - std::lock_guard<std::mutex> locker(m_vtable_mutex); - auto pos = m_vtable_info_map.find(vtable_addr); - if (pos != m_vtable_info_map.end()) + auto vtable_info_map = m_vtable_info_map.Lock(); + auto pos = vtable_info_map->find(vtable_addr); + if (pos != vtable_info_map->end()) return pos->second; } @@ -830,8 +830,7 @@ CPPLanguageRuntime::GetVTableInfoEntry(ValueObject &in_value, bool check_type) { /*info=*/VTableInfo{vtable_addr, symbol}, /*runtime=*/runtime.get(), }; - std::lock_guard<std::mutex> locker(m_vtable_mutex); - m_vtable_info_map[vtable_addr] = entry; + (*m_vtable_info_map.Lock())[vtable_addr] = entry; return entry; } } diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h index 823a968cbad8c..5bc21448ce306 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h @@ -16,6 +16,7 @@ #include "CommonABIRuntime.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Target/LanguageRuntime.h" +#include "lldb/Utility/Locked.h" #include "lldb/lldb-private.h" namespace lldb_private { @@ -153,8 +154,8 @@ class CPPLanguageRuntime : public LanguageRuntime { llvm::Expected<VTableInfoEntry> GetVTableInfoEntry(ValueObject &in_value, bool check_type); - std::map<Address, VTableInfoEntry> m_vtable_info_map; - std::mutex m_vtable_mutex; + using VTableInfoMap = std::map<Address, VTableInfoEntry>; + Guarded<VTableInfoMap, std::mutex> m_vtable_info_map; }; } // namespace lldb_private diff --git a/lldb/unittests/Utility/LockedTest.cpp b/lldb/unittests/Utility/LockedTest.cpp index cae24293dee2e..f898f21b56291 100644 --- a/lldb/unittests/Utility/LockedTest.cpp +++ b/lldb/unittests/Utility/LockedTest.cpp @@ -225,3 +225,40 @@ TEST(LockedTest, ExclusiveAccessOnRWMutex) { writer->value = 11; EXPECT_EQ(widget.value, 11); } + +// Guarded is neither copyable nor movable. +static_assert(!std::is_copy_constructible_v<Guarded<Widget>>); +static_assert(!std::is_move_constructible_v<Guarded<Widget>>); + +TEST(LockedTest, GuardedDefaultConstructed) { + Guarded<Widget> guarded; + EXPECT_EQ(guarded.Lock()->value, 0); +} + +TEST(LockedTest, GuardedValueConstructed) { + Guarded<Widget> guarded(Widget{42}); + EXPECT_EQ(guarded.Lock()->value, 42); +} + +TEST(LockedTest, GuardedExclusiveAccessMutatesValue) { + Guarded<Widget> guarded; + guarded.Lock()->value = 7; + EXPECT_EQ(guarded.Lock()->value, 7); +} + +TEST(LockedTest, GuardedSharedAccessIsReadOnly) { + Guarded<Widget> guarded(Widget{5}); + SharedLocked<const Widget *, llvm::sys::RWMutex> reader = + guarded.LockShared(); + EXPECT_EQ(reader->value, 5); + static_assert(std::is_same_v<decltype(reader.get()), const Widget *>, + "shared access borrows a const-qualified pointer"); +} + +// std::shared_mutex satisfies SharedLockable too, so Guarded works with it +// as a drop-in replacement for llvm::sys::RWMutex. +TEST(LockedTest, GuardedWorksWithStdSharedMutex) { + Guarded<Widget, std::shared_mutex> guarded; + guarded.Lock()->value = 3; + EXPECT_EQ(guarded.LockShared()->value, 3); +} `````````` </details> https://github.com/llvm/llvm-project/pull/219428 _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
