This is an archive of the discontinued LLVM Phabricator instance.

[lldb][NFC] Make metadata tracking type safe
ClosedPublic

Authored by teemperor on Dec 12 2019, 4:20 AM.
Tokens
"Pterodactyl" token, awarded by JDevlieghere.

Details

Summary

LLDB associates additional information with Types and Declarations which it calls ClangASTMetadata.
ClangASTMetadata is stored by the ClangASTSourceCommon which is implemented by having a large map of
void * keys to associated ClangASTMetadata values. To make this whole mechanism even unsafer
we also decided to use clang::Decl * as one of pointers we throw in there (beside clang::Type *).

The Decl class hierarchy uses multiple inheritance which means that not all pointers have the
same address when they are implicitly converted to pointers of their parent classes. For example
clang::Decl * and clang::DeclContext * won't end up being the same address when they
are implicitly converted from one of the many Decl-subclasses that inherit from both.

As we use the addresses as the keys in our Metadata map, this means that any implicit type
conversions to parent classes (or anything else that changes the addresses) will break our metadata tracking
in obscure ways.

Just to illustrate how broken this whole mechanism currently is:

// m_ast is our ClangASTContext. Let's double check that from GetTranslationUnitDecl
// in ClangASTContext and ASTContext return the same thing (one method just calls the other).
assert(m_ast->GetTranslationUnitDecl() == m_ast->getASTContext()->getTranslationUnitDecl());
// Ok, both methods have the same TU*. Let's store metadata with the result of one method call.
m_ast->SetMetadataAsUserID(m_ast->GetTranslationUnitDecl(), 1234U);
// Retrieve the same Metadata for the TU by using the TU* from the other method... which fails?
EXPECT_EQ(m_ast->GetMetadata(m_ast->getASTContext()->getTranslationUnitDecl())->GetUserID(), 1234U);
// Turns out that getTranslationUnitDecl one time returns a TranslationUnitDecl* but the other time
// we return one of the parent classes of TranslationUnitDecl (DeclContext).

This patch splits up the void * API into two where one does the clang::Type * tracking and one the clang::Decl * mapping.
Type and Decl are disjoint class hierarchies so there is no implicit conversion possible that could influence
the address values.

I had to change the storing of clang::QualType opaque pointers to their clang::Type * equivalents as
opaque pointers are already void * pointers to begin with. We don't seem to ever set any qualifier in any of these
QualTypes to this conversion should be NFC.

Diff Detail

Event Timeline

teemperor created this revision.Dec 12 2019, 4:20 AM
Herald added a project: Restricted Project. · View Herald TranscriptDec 12 2019, 4:20 AM

(I'm aware that a lot of the touched code here could be improved, but I would prefer that I at least can trust my compiler before I refactor the remaining Metadata stuff...)

teemperor edited the summary of this revision. (Show Details)Dec 12 2019, 4:24 AM
labath accepted this revision.Dec 12 2019, 5:00 AM

Yes this is definitely better. If storing metadata for QualTypes is important (my impression is it's the opposite), then you could do that (while maintaining a decent amount of type safety) by having the [GS]etMetadata functions take a QualType, and converting it to void* only as an implementation detail..

This revision is now accepted and ready to land.Dec 12 2019, 5:00 AM
aprantl added inline comments.Dec 12 2019, 9:18 AM
lldb/source/Symbol/ClangExternalASTSourceCommon.cpp
64

.lookup(), assuming this is a DenseMap?

teemperor marked an inline comment as done.Dec 13 2019, 2:52 AM
teemperor added inline comments.
lldb/source/Symbol/ClangExternalASTSourceCommon.cpp
64

We can't use it here as we return a pointer to the internally stored value in the map and not a value :(

This revision was automatically updated to reflect the committed changes.