Skip to content

Commit ebe8b80

Browse files
committed
[lldb][TypeSystemClang] Avoid accessing definition if none is available
We've been hitting cases where LLDB marks a decl as `isCompleteDefinition` but no definition was allocated for it. Then when we access a an API in which Clang assumes a definition exists, and dereferences a nullptr. In the specific case that happens when we've incorrectly been keeping track of the `ImportedDecls` in `clang::ASTImporter` (which manifests as trying to `MapImported` on two different destination decls from the same source decl for the same ClangASTImporterDelegate). The more fundmental issue is that we're failing to complete the type properly. But the fix for that is still in-progress. So we're working around the crash by guarding against failed type completion. rdar://133958782
1 parent c034db5 commit ebe8b80

File tree

1 file changed

+20
-3
lines changed

1 file changed

+20
-3
lines changed

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "TypeSystemClang.h"
1010

1111
#include "clang/AST/DeclBase.h"
12+
#include "clang/AST/DeclCXX.h"
1213
#include "clang/AST/ExprCXX.h"
1314
#include "llvm/ADT/STLForwardCompat.h"
1415
#include "llvm/Support/Casting.h"
@@ -3650,6 +3651,15 @@ bool TypeSystemClang::IsPolymorphicClass(lldb::opaque_compiler_type_t type) {
36503651
return false;
36513652
}
36523653

3654+
/// Returns 'true' if \ref decl has been allocated a definition
3655+
/// *and* the definition was marked as completed. There are currently
3656+
/// situations in which LLDB marks a definition as `isCompleteDefinition`
3657+
/// while no definition was allocated. This function guards against those
3658+
/// situations.
3659+
static bool HasCompleteDefinition(clang::CXXRecordDecl *decl) {
3660+
return decl && decl->hasDefinition() && decl->isCompleteDefinition();
3661+
}
3662+
36533663
bool TypeSystemClang::IsPossibleDynamicType(lldb::opaque_compiler_type_t type,
36543664
CompilerType *dynamic_pointee_type,
36553665
bool check_cplusplus,
@@ -3732,8 +3742,9 @@ bool TypeSystemClang::IsPossibleDynamicType(lldb::opaque_compiler_type_t type,
37323742
if (check_cplusplus) {
37333743
clang::CXXRecordDecl *cxx_record_decl =
37343744
pointee_qual_type->getAsCXXRecordDecl();
3745+
37353746
if (cxx_record_decl) {
3736-
bool is_complete = cxx_record_decl->isCompleteDefinition();
3747+
bool is_complete = HasCompleteDefinition(cxx_record_decl);
37373748

37383749
if (is_complete)
37393750
success = cxx_record_decl->isDynamicClass();
@@ -3742,7 +3753,9 @@ bool TypeSystemClang::IsPossibleDynamicType(lldb::opaque_compiler_type_t type,
37423753
if (metadata)
37433754
success = metadata->GetIsDynamicCXXType();
37443755
else {
3745-
is_complete = GetType(pointee_qual_type).GetCompleteType();
3756+
// Make sure completion has actually completed the type.
3757+
is_complete = GetType(pointee_qual_type).GetCompleteType() &&
3758+
HasCompleteDefinition(cxx_record_decl);
37463759
if (is_complete)
37473760
success = cxx_record_decl->isDynamicClass();
37483761
else
@@ -5478,8 +5491,12 @@ TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type,
54785491
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
54795492
const clang::RecordDecl *record_decl = record_type->getDecl();
54805493
assert(record_decl);
5494+
5495+
// CXXBaseSpecifiers are stored on the definition. If we don't have
5496+
// one at this point that means we "completed" the type without actually
5497+
// having allocated a definition.
54815498
const clang::CXXRecordDecl *cxx_record_decl =
5482-
llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
5499+
llvm::dyn_cast<clang::CXXRecordDecl>(record_decl)->getDefinition();
54835500
if (cxx_record_decl) {
54845501
if (omit_empty_base_classes) {
54855502
// Check each base classes to see if it or any of its base classes

0 commit comments

Comments
 (0)