-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[lldb] Fix crash when adding members to an "incomplete" type #102116
Conversation
This fixes a regression caused by delayed type definition searching (llvm#96755 and friends): If we end up adding a member (e.g. a typedef) to a type that we've already attempted to complete (and failed), the resulting AST would end up inconsistent (we would start to "forcibly" complete it, but never finish it), and importing it into an expression AST would crash. This patch fixes this by detecting the situation and finishing the definition as well.
@llvm/pr-subscribers-lldb Author: Pavel Labath (labath) ChangesThis fixes a regression caused by delayed type definition searching (#96755 and friends): If we end up adding a member (e.g. a typedef) to a type that we've already attempted to complete (and failed), the resulting AST would end up inconsistent (we would start to "forcibly" complete it, but never finish it), and importing it into an expression AST would crash. This patch fixes this by detecting the situation and finishing the definition as well. Full diff: https://github.com/llvm/llvm-project/pull/102116.diff 2 Files Affected:
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index a4dcde1629fc2..3968d5bf71e1c 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -269,8 +269,15 @@ static void PrepareContextToReceiveMembers(TypeSystemClang &ast,
}
// We don't have a type definition and/or the import failed, but we need to
- // add members to it. Start the definition to make that possible.
- tag_decl_ctx->startDefinition();
+ // add members to it. Start the definition to make that possible. If the type
+ // has no external storage we also have to complete the definition. Otherwise,
+ // that will happen when we are asked to complete the type
+ // (CompleteTypeFromDWARF).
+ ast.StartTagDeclarationDefinition(type);
+ if (!tag_decl_ctx->hasExternalLexicalStorage()) {
+ ast.SetDeclIsForcefullyCompleted(tag_decl_ctx);
+ ast.CompleteTagDeclarationDefinition(type);
+ }
}
ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) {
diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/typedef-in-incomplete-type.cpp b/lldb/test/Shell/SymbolFile/DWARF/x86/typedef-in-incomplete-type.cpp
new file mode 100644
index 0000000000000..47ea1e2639c6e
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/DWARF/x86/typedef-in-incomplete-type.cpp
@@ -0,0 +1,23 @@
+// RUN: %clangxx --target=x86_64-pc-linux -o %t -c %s -g
+// RUN: %lldb %t -o "target var a" -o "expr -- var" -o exit | FileCheck %s
+
+// This forces lldb to attempt to complete the type A. Since it has no
+// definition it will fail.
+// CHECK: target var a
+// CHECK: (A) a = <incomplete type "A">
+
+// Now attempt to display the second variable, which will try to add a typedef
+// to the incomplete type. Make sure that succeeds. Use the expression command
+// to make sure the resulting AST can be imported correctly.
+// CHECK: expr -- var
+// CHECK: (A::X) $0 = 0
+
+struct A {
+ // Declare the constructor, but don't define it to avoid emitting the
+ // definition in the debug info.
+ A();
+ using X = int;
+};
+
+A a;
+A::X var;
|
@@ -0,0 +1,23 @@ | |||
// RUN: %clangxx --target=x86_64-pc-linux -o %t -c %s -g |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would only crash with -flimit-debug-info
right? Could we add that here?
Also should we move it to the non-x86 directory? Not sure what the intent behind the x86 directory is but it would be nice to get the coverage when running this on ARM machines too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would only crash with -flimit-debug-info right?
Correct. The type definition needs to be absent from the binary and the ~only way to achieve that is to compile at least a part of it with -flimit-debug-info. I will add that explicitly.
Not sure what the intent behind the x86 directory is but it would be nice to get the coverage when running this on ARM machines too
The x86 directory is conditionalized on the x86 target, so it will run whenever the local build supports the x86 architecture (ie X86
is in LLVM_TARGETS_TO_BUILD
), regardless of the actual host architecture. (i.e., it works the same as as x86
directories in llvm)
The goal here isn't so much to hardcode the architecture (to x86), as much it is to hardcode the file format (to non-windows). We don't support working with unlinked object files on windows, and if I tried to link things then I'd need to depend on the linker and pull in other platform-specific stuff, which would make the test non-minimal.
The thing I like about a test like this is that it (again, like the llvm tests) runs the same way everywhere, so there's little risk of needing to scrable to find a freebsd-mips (I'm exaggerating, I know) machine to reproduce a problem somewhere. (And I would totally love if we had more tests hardcoding aarch64-macosx triples so I can get more macos coverage without switching to a mac machine)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh got it
I saw the tests in this directory weren't run on my M1 and misinterpreted that.
The thing I like about a test like this is that it (again, like the llvm tests) runs the same way everywhere, so there's little risk of needing to scrable to find a freebsd-mips (I'm exaggerating, I know) machine to reproduce a problem somewhere.
Agreed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
So the actual problem is that the ASTImporter will only copy over the definition to the destination decl if the source decl isCompleteDefinition
. So then when we tried to add the typedef decl to the CXXRecordDecl
that the ASTImporter created for A
, it would try to query its definition which didn't get copied over (cause we only ever started the definition for A
, but nothing completed it, especially since it had no external storage), and hence we assert.
No, the problem was that |
Yea agreed. I was just curious where exactly the difference in the ASTImporter codepath came from with/without the patch. And it looks like without completing the definition, we lose the |
You're right -- I misremembered. I thought the DefinitionData is set when completing the definition, but it happens when the definition is started. In that case, yes, the crash happened because the ast importer didn't copy over the definition data, but then tried to access it when adding the typedef. |
/cherry-pick 57cd100 |
Failed to cherry-pick: 57cd100 https://github.com/llvm/llvm-project/actions/runs/10352006063 Please manually backport the fix and push it to your github fork. Once this is done, please create a pull request |
/cherry-pick 57cd100 |
…2116) This fixes a regression caused by delayed type definition searching (llvm#96755 and friends): If we end up adding a member (e.g. a typedef) to a type that we've already attempted to complete (and failed), the resulting AST would end up inconsistent (we would start to "forcibly" complete it, but never finish it), and importing it into an expression AST would crash. This patch fixes this by detecting the situation and finishing the definition as well. (cherry picked from commit 57cd100)
/pull-request #102895 |
…2116) This fixes a regression caused by delayed type definition searching (llvm#96755 and friends): If we end up adding a member (e.g. a typedef) to a type that we've already attempted to complete (and failed), the resulting AST would end up inconsistent (we would start to "forcibly" complete it, but never finish it), and importing it into an expression AST would crash. This patch fixes this by detecting the situation and finishing the definition as well. (cherry picked from commit 57cd100)
…2116) This fixes a regression caused by delayed type definition searching (llvm#96755 and friends): If we end up adding a member (e.g. a typedef) to a type that we've already attempted to complete (and failed), the resulting AST would end up inconsistent (we would start to "forcibly" complete it, but never finish it), and importing it into an expression AST would crash. This patch fixes this by detecting the situation and finishing the definition as well.
This fixes a regression caused by delayed type definition searching (#96755 and friends): If we end up adding a member (e.g. a typedef) to a type that we've already attempted to complete (and failed), the resulting AST would end up inconsistent (we would start to "forcibly" complete it, but never finish it), and importing it into an expression AST would crash.
This patch fixes this by detecting the situation and finishing the definition as well.