aprantl created this revision.
aprantl added reviewers: kastiglione, jingham, labath.
Herald added a project: All.
aprantl requested review of this revision.

When a process gets restarted TypeSystem objects associated with it may get 
deleted, and any CompilerType objects holding on to a reference to that type 
system are a use-after-free in waiting. Because of the SBAPI, we don't have 
tight control over where CompilerTypes go and when they are used. This is 
particularly a problem in the Swift plugin, where the scratch TypeSystem can be 
restarted while the process is still running. The Swift plugin has a lock to 
prevent abuse, but where there's a lock there can be bugs.

To help diagnose these hard-to-debug problems (and because Halloween is right 
around the corner) this patch introduces a global TypeSystem graveyard that 
collects all dead TypeSystem pointers and checks against it in 
CompilerType::IsValid(). This is intended as a bug-finding tool, which is why 
this triggers lldbassert(). Compared to everything else LLDB is doing the extra 
DenseMap lookup and lock should be negligible, which is why this feature is 
turned on even in release mode.

rdar://101505232


https://reviews.llvm.org/D136650

Files:
  lldb/include/lldb/Symbol/CompilerType.h
  lldb/include/lldb/Symbol/TypeSystem.h
  lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
  lldb/source/Symbol/CompilerType.cpp
  lldb/source/Symbol/TypeSystem.cpp
  lldb/unittests/Symbol/TestTypeSystemClang.cpp

Index: lldb/unittests/Symbol/TestTypeSystemClang.cpp
===================================================================
--- lldb/unittests/Symbol/TestTypeSystemClang.cpp
+++ lldb/unittests/Symbol/TestTypeSystemClang.cpp
@@ -29,6 +29,7 @@
   void SetUp() override {
     m_ast.reset(
         new TypeSystemClang("test ASTContext", HostInfo::GetTargetTriple()));
+    GetTypeSystemGraveyard().Erase(m_ast.get());
   }
 
   void TearDown() override { m_ast.reset(); }
Index: lldb/source/Symbol/TypeSystem.cpp
===================================================================
--- lldb/source/Symbol/TypeSystem.cpp
+++ lldb/source/Symbol/TypeSystem.cpp
@@ -17,6 +17,12 @@
 using namespace lldb_private;
 using namespace lldb;
 
+TypeSystemSet &lldb_private::GetTypeSystemGraveyard() {
+  // Intentionally leaked to avoid C++ destructor ordering issue.
+  static TypeSystemSet *g_typesystem_graveyard = new TypeSystemSet();
+  return *g_typesystem_graveyard;
+}
+
 /// A 64-bit SmallBitVector is only small up to 64-7 bits, and the
 /// setBitsInMask interface wants to write full bytes.
 static const size_t g_num_small_bitvector_bits = 64 - 8;
@@ -35,7 +41,11 @@
 bool LanguageSet::Empty() const { return bitvector.none(); }
 bool LanguageSet::operator[](unsigned i) const { return bitvector[i]; }
 
-TypeSystem::~TypeSystem() = default;
+TypeSystem::TypeSystem() {
+  // Remove this pointer from the graveyard in case it got reused.
+  GetTypeSystemGraveyard().Erase(this);
+}
+void TypeSystem::Finalize() { GetTypeSystemGraveyard().Insert(this, false); }
 
 static lldb::TypeSystemSP CreateInstanceHelper(lldb::LanguageType language,
                                                Module *module, Target *target) {
Index: lldb/source/Symbol/CompilerType.cpp
===================================================================
--- lldb/source/Symbol/CompilerType.cpp
+++ lldb/source/Symbol/CompilerType.cpp
@@ -11,11 +11,13 @@
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/StreamFile.h"
 #include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/TypeSystem.h"
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Utility/ConstString.h"
 #include "lldb/Utility/DataBufferHeap.h"
 #include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/LLDBAssert.h"
 #include "lldb/Utility/Scalar.h"
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/StreamString.h"
@@ -26,6 +28,17 @@
 using namespace lldb;
 using namespace lldb_private;
 
+bool CompilerType::IsValid() const {
+  if (!m_type || !m_type_system)
+    return false;
+  bool unused;
+  if (GetTypeSystemGraveyard().Lookup(m_type_system, unused)) {
+    lldbassert(false && "CompilerType belongs to deleted Typesystem");
+    return false;
+  }
+  return true;
+}
+
 // Tests
 
 bool CompilerType::IsAggregateType() const {
Index: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
===================================================================
--- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -552,7 +552,8 @@
 }
 
 TypeSystemClang::TypeSystemClang(llvm::StringRef name,
-                                 llvm::Triple target_triple) {
+                                 llvm::Triple target_triple)
+    : TypeSystem() {
   m_display_name = name.str();
   if (!target_triple.str().empty())
     SetTargetTriple(target_triple.str());
@@ -562,7 +563,8 @@
 }
 
 TypeSystemClang::TypeSystemClang(llvm::StringRef name,
-                                 ASTContext &existing_ctxt) {
+                                 ASTContext &existing_ctxt)
+    : TypeSystem() {
   m_display_name = name.str();
   SetTargetTriple(existing_ctxt.getTargetInfo().getTriple().str());
 
@@ -661,6 +663,7 @@
   m_diagnostics_engine_up.reset();
   m_source_manager_up.reset();
   m_language_options_up.reset();
+  TypeSystem::Finalize();
 }
 
 void TypeSystemClang::setSema(Sema *s) {
Index: lldb/include/lldb/Symbol/TypeSystem.h
===================================================================
--- lldb/include/lldb/Symbol/TypeSystem.h
+++ lldb/include/lldb/Symbol/TypeSystem.h
@@ -21,6 +21,7 @@
 #include "llvm/Support/Error.h"
 
 #include "lldb/Core/PluginInterface.h"
+#include "lldb/Core/ThreadSafeDenseMap.h"
 #include "lldb/Expression/Expression.h"
 #include "lldb/Symbol/CompilerDecl.h"
 #include "lldb/Symbol/CompilerDeclContext.h"
@@ -74,7 +75,8 @@
 class TypeSystem : public PluginInterface {
 public:
   // Constructors and Destructors
-  ~TypeSystem() override;
+  TypeSystem();
+  ~TypeSystem() = default;
 
   // LLVM RTTI support
   virtual bool isA(const void *ClassID) const = 0;
@@ -87,7 +89,7 @@
 
   // Free up any resources associated with this TypeSystem.  Done before
   // removing all the TypeSystems from the TypeSystemMap.
-  virtual void Finalize() {}
+  virtual void Finalize();
 
   virtual DWARFASTParser *GetDWARFParser() { return nullptr; }
   virtual PDBASTParser *GetPDBParser() { return nullptr; }
@@ -558,6 +560,12 @@
       llvm::Optional<CreateCallback> create_callback = llvm::None);
 };
 
+using TypeSystemSet =
+    ThreadSafeDenseMap<TypeSystem *, bool, std::recursive_mutex>;
+/// A set of type systems that have been deleted and can no longer be accessed.
+/// The bool value is unused.
+TypeSystemSet &GetTypeSystemGraveyard();
+  
 } // namespace lldb_private
 
 #endif // LLDB_SYMBOL_TYPESYSTEM_H
Index: lldb/include/lldb/Symbol/CompilerType.h
===================================================================
--- lldb/include/lldb/Symbol/CompilerType.h
+++ lldb/include/lldb/Symbol/CompilerType.h
@@ -66,10 +66,10 @@
   /// Tests.
   /// \{
   explicit operator bool() const {
-    return m_type != nullptr && m_type_system != nullptr;
+    return IsValid();
   }
 
-  bool IsValid() const { return m_type != nullptr && m_type_system != nullptr; }
+  bool IsValid() const;
 
   bool IsArrayType(CompilerType *element_type = nullptr,
                    uint64_t *size = nullptr,
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to