[Lldb-commits] [lldb] r241695 - Fixed a serious bug in DeportType where the types could retain DeclContexts that

Sean Callanan scallanan at apple.com
Wed Jul 8 11:03:41 PDT 2015


Author: spyffe
Date: Wed Jul  8 13:03:41 2015
New Revision: 241695

URL: http://llvm.org/viewvc/llvm-project?rev=241695&view=rev
Log:
Fixed a serious bug in DeportType where the types could retain DeclContexts that
pointed into the artificial function constructed for the expression.  I now make
anything that pointed to the function as its DeclContext be global while the
copy occurs; afterward I restored the old DeclContext.

Added a testcase that make sure that this works properly and doesn't crash
anything.

<rdar://problem/21049838>

Modified:
    lldb/trunk/source/Symbol/ClangASTImporter.cpp
    lldb/trunk/test/expression_command/persistent_types/TestPersistentTypes.py

Modified: lldb/trunk/source/Symbol/ClangASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/ClangASTImporter.cpp?rev=241695&r1=241694&r2=241695&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/ClangASTImporter.cpp (original)
+++ lldb/trunk/source/Symbol/ClangASTImporter.cpp Wed Jul  8 13:03:41 2015
@@ -17,6 +17,7 @@
 #include "lldb/Symbol/ClangASTImporter.h"
 #include "lldb/Symbol/ClangExternalASTSourceCommon.h"
 #include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Utility/LLDBAssert.h"
 
 using namespace lldb_private;
 using namespace clang;
@@ -109,6 +110,134 @@ ClangASTImporter::CopyDecl (clang::ASTCo
     return nullptr;
 }
 
+class DeclContextOverride
+{
+private:
+    struct Backup
+    {
+        clang::DeclContext *decl_context;
+        clang::DeclContext *lexical_decl_context;
+    };
+    
+    std::map<clang::Decl *, Backup> m_backups;
+    
+    void OverrideOne(clang::Decl *decl)
+    {
+        if (m_backups.find(decl) != m_backups.end())
+        {
+            return;
+        }
+            
+        m_backups[decl] = { decl->getDeclContext(), decl->getLexicalDeclContext() };
+        
+        decl->setDeclContext(decl->getASTContext().getTranslationUnitDecl());
+        decl->setLexicalDeclContext(decl->getASTContext().getTranslationUnitDecl());
+    }
+    
+    bool ChainPassesThrough(clang::Decl *decl,
+                            clang::DeclContext *base,
+                            clang::DeclContext *(clang::Decl::*contextFromDecl)(),
+                            clang::DeclContext *(clang::DeclContext::*contextFromContext)())
+    {
+        for (DeclContext *decl_ctx = (decl->*contextFromDecl)();
+             decl_ctx;
+             decl_ctx = (decl_ctx->*contextFromContext)())
+        {
+            if (decl_ctx == base)
+            {
+                return true;
+            }
+        }
+        
+        return false;
+    }
+    
+    clang::Decl *GetEscapedChild(clang::Decl *decl, clang::DeclContext *base = nullptr)
+    {
+        if (base)
+        {
+            // decl's DeclContext chains must pass through base.
+            
+            if (!ChainPassesThrough(decl, base, &clang::Decl::getDeclContext, &clang::DeclContext::getParent) ||
+                !ChainPassesThrough(decl, base, &clang::Decl::getLexicalDeclContext, &clang::DeclContext::getLexicalParent))
+            {
+                return decl;
+            }
+        }
+        else
+        {
+            base = clang::dyn_cast<clang::DeclContext>(decl);
+            
+            if (!base)
+            {
+                return nullptr;
+            }
+        }
+        
+        if (clang::DeclContext *context = clang::dyn_cast<clang::DeclContext>(decl))
+        {
+            for (clang::Decl *decl : context->decls())
+            {
+                if (clang::Decl *escaped_child = GetEscapedChild(decl))
+                {
+                    return escaped_child;
+                }
+            }
+        }
+        
+        return nullptr;
+    }
+    
+    void Override(clang::Decl *decl)
+    {
+        if (clang::Decl *escaped_child = GetEscapedChild(decl))
+        {
+            Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+            
+            if (log)
+                log->Printf("    [ClangASTImporter] DeclContextOverride couldn't override (%sDecl*)%p - its child (%sDecl*)%p escapes",
+                            decl->getDeclKindName(), static_cast<void*>(decl),
+                            escaped_child->getDeclKindName(), static_cast<void*>(escaped_child));
+            lldbassert(0 && "Couldn't override!");
+        }
+        
+        OverrideOne(decl);
+    }
+    
+public:
+    DeclContextOverride()
+    {
+    }
+    
+    void OverrideAllDeclsFromContainingFunction(clang::Decl *decl)
+    {
+        for (DeclContext *decl_context = decl->getLexicalDeclContext();
+             decl_context;
+             decl_context = decl_context->getLexicalParent())
+        {
+            DeclContext *redecl_context = decl_context->getRedeclContext();
+            
+            if (llvm::isa<FunctionDecl>(redecl_context) &&
+                llvm::isa<TranslationUnitDecl>(redecl_context->getLexicalParent()))
+            {
+                for (clang::Decl *child_decl : decl_context->decls())
+                {
+                    Override(child_decl);
+                }
+            }
+        }
+    }
+    
+    ~DeclContextOverride()
+    {
+        for (const std::pair<clang::Decl *, Backup> &backup : m_backups)
+        {
+            backup.first->setDeclContext(backup.second.decl_context);
+            backup.first->setLexicalDeclContext(backup.second.lexical_decl_context);
+        }
+    }
+};
+
 lldb::clang_type_t
 ClangASTImporter::DeportType (clang::ASTContext *dst_ctx,
                               clang::ASTContext *src_ctx,
@@ -122,6 +251,13 @@ ClangASTImporter::DeportType (clang::AST
     std::set<NamedDecl *> decls_to_deport;
     std::set<NamedDecl *> decls_already_deported;
     
+    DeclContextOverride decl_context_override;
+    
+    if (const clang::TagType *tag_type = clang::QualType::getFromOpaquePtr(type)->getAs<TagType>())
+    {
+        decl_context_override.OverrideAllDeclsFromContainingFunction(tag_type->getDecl());
+    }
+    
     minion_sp->InitDeportWorkQueues(&decls_to_deport,
                                     &decls_already_deported);
     
@@ -156,6 +292,10 @@ ClangASTImporter::DeportDecl (clang::AST
 
     std::set<NamedDecl *> decls_to_deport;
     std::set<NamedDecl *> decls_already_deported;
+    
+    DeclContextOverride decl_context_override;
+    
+    decl_context_override.OverrideAllDeclsFromContainingFunction(decl);
 
     minion_sp->InitDeportWorkQueues(&decls_to_deport,
                                     &decls_already_deported);

Modified: lldb/trunk/test/expression_command/persistent_types/TestPersistentTypes.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/expression_command/persistent_types/TestPersistentTypes.py?rev=241695&r1=241694&r2=241695&view=diff
==============================================================================
--- lldb/trunk/test/expression_command/persistent_types/TestPersistentTypes.py (original)
+++ lldb/trunk/test/expression_command/persistent_types/TestPersistentTypes.py Wed Jul  8 13:03:41 2015
@@ -46,6 +46,12 @@ class PersistenttypesTestCase(TestBase):
         self.expect("expression struct { int a; int b; } x = { 2, 3 }; x",
                     substrs = ['a = 2', 'b = 3'])
 
+        self.expect("expression struct { int x; int y; int z; } object; object.y = 1; object.z = 3; object.x = 2; object",
+                    substrs = ['x = 2', 'y = 1', 'z = 3'])
+
+        self.expect("expression struct A { int x; int y; }; struct { struct A a; int z; } object; object.a.y = 1; object.z = 3; object.a.x = 2; object",
+                    substrs = ['x = 2', 'y = 1', 'z = 3'])
+
 
 if __name__ == '__main__':
     import atexit





More information about the lldb-commits mailing list