Skip to content

[Clang][Sema] set declaration invalid earlier to prevent crash in calculating record layout #87173

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

Merged
merged 1 commit into from
Apr 18, 2024

Conversation

jcsxky
Copy link
Contributor

@jcsxky jcsxky commented Mar 31, 2024

Try to fix #75221
This crash caused by calculating record layout which contains a field declaration with dependent type. Make it invalid before it is a complete definition to prevent this crash. Define a new scope type to record this type alias and set the record declaration invalid when it is defined in a type alias template.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Mar 31, 2024
@llvmbot
Copy link
Member

llvmbot commented Mar 31, 2024

@llvm/pr-subscribers-clang

Author: Qizhi Hu (jcsxky)

Changes

Try to fix #75221
This crash caused by calculating record layout which contains a field declaration with dependent type. Make it invalid when report diagnose to prevent this crash. Set the record declaration incomplete bypass the assertion and restore the status when finish setting it invalid.


Full diff: https://github.com/llvm/llvm-project/pull/87173.diff

3 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+2)
  • (modified) clang/lib/Sema/SemaType.cpp (+3)
  • (added) clang/test/SemaCXX/PR75221.cpp (+7)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 37b843915a0dee..20578c9b60e33c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -465,6 +465,8 @@ Bug Fixes to C++ Support
   following the first `::` were ignored).
 - Fix an out-of-bounds crash when checking the validity of template partial specializations. (part of #GH86757).
 - Fix an issue caused by not handling invalid cases when substituting into the parameter mapping of a constraint. Fixes (#GH86757).
+- Fix a crash caused by defined struct in a type alias template when the structure
+  has fields with dependent type. Fixes (#GH75221).
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index fd94caa4e1d449..973ad20c943bde 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -3899,6 +3899,9 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
       SemaRef.Diag(OwnedTagDecl->getLocation(), DiagID)
           << SemaRef.Context.getTypeDeclType(OwnedTagDecl);
       D.setInvalidType(true);
+      OwnedTagDecl->setCompleteDefinition(false);
+      OwnedTagDecl->setInvalidDecl();
+      OwnedTagDecl->setCompleteDefinition();
     }
   }
 
diff --git a/clang/test/SemaCXX/PR75221.cpp b/clang/test/SemaCXX/PR75221.cpp
new file mode 100644
index 00000000000000..08b7a06676a8a5
--- /dev/null
+++ b/clang/test/SemaCXX/PR75221.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -verify -std=c++11 -fsyntax-only %s
+// expected-no-diagnostics
+
+template <class T> using foo = struct foo {
+  T size = 0;
+};
+foo a;

@@ -3899,6 +3899,9 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
SemaRef.Diag(OwnedTagDecl->getLocation(), DiagID)
<< SemaRef.Context.getTypeDeclType(OwnedTagDecl);
D.setInvalidType(true);
OwnedTagDecl->setCompleteDefinition(false);
OwnedTagDecl->setInvalidDecl();
OwnedTagDecl->setCompleteDefinition();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure the OwnedTagDecl is ALWAYS a complete definition here? Should we cache the existing value before 3902 and restore that rather than always setting it complete?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am little uncomfortable with this change here, I see that you are calling setCompleteDefinition(false) in order to get around the assert that the decl is not complete in Decl::setInvalidDecl(...). If this precondition is not true we need to understand why it break down or if this implies we should be handling this differently.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetDeclSpecTypeForDeclarator is called from two places GetTypeForDeclaratorCast(...) and where that is called D.isInvalidType() is checked. It is also called from GetTypeForDeclarator(...) and the checking of after that call is a bit more varied. I am wondering if we are being sloppy in one of those calls.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@erichkeane Condition holds in outer if(line 3841) indicates OwnedTagDecl is a complete definition.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shafik If I understand correctly, you want to set OwnedTagDecl invalid before it is a complete definition. I will look into the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#0  clang::TagDecl::setCompleteDefinition (this=0x5555556cabd8, V=true) at /home/huqizhi/llvm-project/clang/include/clang/AST/Decl.h:3656
#1  0x00007fffe775b540 in clang::TagDecl::completeDefinition (this=0x5555556cabd8) at /home/huqizhi/llvm-project/clang/lib/AST/Decl.cpp:4720
#2  0x00007fffe775d110 in clang::RecordDecl::completeDefinition (this=0x5555556cabd8) at /home/huqizhi/llvm-project/clang/lib/AST/Decl.cpp:5049
#3  0x00007fffe779be00 in clang::CXXRecordDecl::completeDefinition (this=0x5555556cabd8, FinalOverriders=0x0) at /home/huqizhi/llvm-project/clang/lib/AST/DeclCXX.cpp:2059
#4  0x00007fffe779bdd9 in clang::CXXRecordDecl::completeDefinition (this=0x5555556cabd8) at /home/huqizhi/llvm-project/clang/lib/AST/DeclCXX.cpp:2055
#5  0x00007fffe44cbab2 in clang::Sema::ActOnFields (this=0x5555556b7060, S=0x5555556d6700, RecLoc=..., EnclosingDecl=0x5555556cabd8, Fields=..., LBrac=..., RBrac=..., Attrs=...)
    at /home/huqizhi/llvm-project/clang/lib/Sema/SemaDecl.cpp:19654
#6  0x00007fffe4636eed in clang::Sema::ActOnFinishCXXMemberSpecification (this=0x5555556b7060, S=0x5555556d6700, RLoc=..., TagDecl=0x5555556cabd8, LBrac=..., RBrac=..., AttrList=...)
    at /home/huqizhi/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp:10540
#7  0x00007fffe5956cf2 in clang::Parser::ParseCXXMemberSpecification (this=0x5555556c4580, RecordLoc=..., AttrFixitLoc=..., Attrs=..., TagType=25, TagDecl=0x5555556cabd8)
    at /home/huqizhi/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp:3782
#8  0x00007fffe5954f8e in clang::Parser::ParseClassSpecifier (this=0x5555556c4580, TagTokKind=clang::tok::kw_struct, StartLoc=..., DS=..., TemplateInfo=..., AS=clang::AS_none, EnteringContext=false, 
    DSC=clang::Parser::DeclSpecContext::DSC_alias_declaration, Attributes=...) at /home/huqizhi/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp:2252
#9  0x00007fffe591b23e in clang::Parser::ParseDeclarationSpecifiers (this=0x5555556c4580, DS=..., TemplateInfo=..., AS=clang::AS_none, DSContext=clang::Parser::DeclSpecContext::DSC_alias_declaration, 
    LateAttrs=0x0, AllowImplicitTypename=clang::ImplicitTypenameContext::Yes) at /home/huqizhi/llvm-project/clang/lib/Parse/ParseDecl.cpp:4553
#10 0x00007fffe59167a3 in clang::Parser::ParseSpecifierQualifierList (this=0x5555556c4580, DS=..., AllowImplicitTypename=clang::ImplicitTypenameContext::Yes, AS=clang::AS_none, 
    DSC=clang::Parser::DeclSpecContext::DSC_alias_declaration) at /home/huqizhi/llvm-project/clang/lib/Parse/ParseDecl.cpp:2829
#11 0x00007fffe592bea4 in clang::Parser::ParseSpecifierQualifierList (this=0x5555556c4580, DS=..., AS=clang::AS_none, DSC=clang::Parser::DeclSpecContext::DSC_alias_declaration)
    at /home/huqizhi/llvm-project/clang/include/clang/Parse/Parser.h:2480
#12 0x00007fffe5906906 in clang::Parser::ParseTypeName (this=0x5555556c4580, Range=0x0, Context=clang::DeclaratorContext::AliasTemplate, AS=clang::AS_none, OwnedType=0x7fffffff8a88, 
    Attrs=0x7fffffff90b0) at /home/huqizhi/llvm-project/clang/lib/Parse/ParseDecl.cpp:59

From the trace we can see that if we want to set OwnedTagDecl invalid before it's a complete definition, Context (DeclaratorContext)should be passed through these funtions (I haven't found how to get this information without passing Context as of now). It's not a better approach than current version from my side. @shafik WDYT?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It DEFINITELY seems strange to me that we're marking this 'complete' before we know if it is valid. So from that perspective, this patch is in the 'wrong' place.

@jcsxky jcsxky requested review from shafik and erichkeane April 8, 2024 09:17
@jcsxky jcsxky force-pushed the fix-75221 branch 2 times, most recently from 26da477 to a0c0fea Compare April 10, 2024 05:36
@jcsxky
Copy link
Contributor Author

jcsxky commented Apr 17, 2024

gently ping. @erichkeane @shafik Any opinions on this pr?

@jcsxky jcsxky merged commit 156ab4d into llvm:main Apr 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

crash on invalid after "error: 'foo' cannot be defined in a type alias template"
4 participants