Skip to content
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

[Clang][Sema] fix crash of attribute transform #78088

Merged
merged 1 commit into from
Jan 26, 2024

Conversation

jcsxky
Copy link
Contributor

@jcsxky jcsxky commented Jan 14, 2024

Try to fix issue

  1. During transforming FunctionProtoType, if ThisContext is nullptr and CurrentContext is ClassTemplateSpecializationDecl, Constructor of CXXThisScopeRAII and Sema::getCurrentThisType won't set CXXThisTypeOverride of Sema. This will lead to building this in RebuildCXXThisExpr with a invalid type(NULL type) and cause crash.
  2. During transforming attribute type, if modifiedType of attribute type is changed, EquivalentType need to be transformed. If EquivalentType is FunctionProtoType, its ParamVarDecl will not be copyed(but parameter num does) and will not be instanced in TransformFunctionTypeParams since ParamVarDecl is nullptr. This will lead to crash in findInstantiationOf(can't find the instance of ParamVarDecl).

This patch tries to fix these issues above.

  1. If CurrentContext is ClassTemplateSpecializationDecl, Use it.
  2. Use EquivalentTypeLoc instead of EquivalentType since it has parameter info. But, if use current TypeLocBuilder, it will crash in TypeLocBuilder::push since LastType is mismatch. Use an auxiliary TypeLocBuilder instead and get transformed EquivalentType.

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

llvmbot commented Jan 14, 2024

@llvm/pr-subscribers-clang

Author: Qizhi Hu (jcsxky)

Changes

Try to fix issue

  1. During transforming FunctionProtoType, if ThisContext, is nullptr and CurrentContext is ClassTemplateSpecializationDecl, Constructor of CXXThisScopeRAII and Sema::getCurrentThisType won't set CXXThisTypeOverride of Sema. This will lead to building this in RebuildCXXThisExpr with a invalid type and cause crash.
  2. During transforming attribute type, if modifiedType of attribute type is changed, EquivalentType will be transformed. If EquivalentType is FunctionProtoType, its ParamVarDecl will not be copyed(but parameter num does) and will not be instanced in TransformFunctionTypeParams since ParamVarDecl is nullptr. This will lead to crash in findInstantiationOf.

This patch tries to fix these issue above.

  1. If CurrentContext is ClassTemplateSpecializationDecl, Use it.
  2. Use EquivalentTypeLoc instead of EquivalentType since it has parameter info. But, if use current TypeLocBuilder, it will crash in TypeLocBuilder::push since LastType is mismatch. Use an auxiliary TypeLocBuilder instead and get transformed EquivalentType.

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

3 Files Affected:

  • (modified) clang/include/clang/AST/TypeLoc.h (+4)
  • (modified) clang/lib/Sema/TreeTransform.h (+8-3)
  • (added) clang/test/Sema/attr-lifetimebound-no-crash.cpp (+15)
diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h
index 471deb14aba51f..04780fdeae3bc1 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -884,6 +884,10 @@ class AttributedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
     return getInnerTypeLoc();
   }
 
+  TypeLoc getEquivalentTypeLoc() const {
+    return TypeLoc(getTypePtr()->getEquivalentType(), getNonLocalData());
+  }
+
   /// The type attribute.
   const Attr *getAttr() const {
     return getLocalData()->TypeAttr;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 1a1bc87d2b3203..be5ba2000de197 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -6124,7 +6124,11 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType(
       //   "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
       //   and the end of the function-definition, member-declarator, or
       //   declarator.
-      Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals);
+      auto *RD =
+          dyn_cast_or_null<CXXRecordDecl>(SemaRef.getCurLexicalContext());
+      Sema::CXXThisScopeRAII ThisScope(
+          SemaRef, ThisContext == nullptr && nullptr != RD ? RD : ThisContext,
+          ThisTypeQuals);
 
       ResultType = getDerived().TransformType(TLB, TL.getReturnLoc());
       if (ResultType.isNull())
@@ -7083,8 +7087,9 @@ QualType TreeTransform<Derived>::TransformAttributedType(
       modifiedType != oldType->getModifiedType()) {
     // TODO: this is really lame; we should really be rebuilding the
     // equivalent type from first principles.
-    QualType equivalentType
-      = getDerived().TransformType(oldType->getEquivalentType());
+    TypeLocBuilder AuxiliaryTLB;
+    QualType equivalentType =
+        getDerived().TransformType(AuxiliaryTLB, TL.getEquivalentTypeLoc());
     if (equivalentType.isNull())
       return QualType();
 
diff --git a/clang/test/Sema/attr-lifetimebound-no-crash.cpp b/clang/test/Sema/attr-lifetimebound-no-crash.cpp
new file mode 100644
index 00000000000000..32e015bab02918
--- /dev/null
+++ b/clang/test/Sema/attr-lifetimebound-no-crash.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+template<typename T>
+struct Bar {
+    int* data;
+
+    auto operator[](const int index) const [[clang::lifetimebound]] -> decltype(data[index]) {
+        return data[index];
+    }
+};
+
+int main() {
+    Bar<int> b;
+    (void)b[2];
+}
\ No newline at end of file

Comment on lines 7088 to 7089
// TODO: this is really lame; we should really be rebuilding the
// equivalent type from first principles.
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment would no longer apply, would it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed, it has been rebuilt using TypeLoc like ModifiedType.

int main() {
Bar<int> b;
(void)b[2];
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing new line

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@jcsxky jcsxky force-pushed the fix_crash_attribute_transform branch from fb6aaee to 55b433e Compare January 17, 2024 05:01
Comment on lines +7088 to +7094
TypeLocBuilder AuxiliaryTLB;
AuxiliaryTLB.reserve(TL.getFullDataSize());
Copy link
Contributor

Choose a reason for hiding this comment

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

an alternative might be to call
TLB.TypeWasModifiedSafely(result) (after the call to getAttributedType below).
I wonder if @AaronBallman has a better alternative

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, I think that's a better approach. Transforming the type should not have changed anything about type location information associated with the type. WDYT @erichkeane ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Right, yeah, the location shouldn't have changed, just the type itself. I think the suggestions above are the way to go.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for your remind! Fixed.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think we need to use AuxiliaryTLB any longer, do we?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I‘m afraid not. It will crash on TypeLocBuilder::pushImpl with the new added test case since TLast == LastTy assert failed if we reuse TLB. Because current FunctionProtoType can't be child of other type node.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah, you're right, we do still need to do that dance it seems.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@cor3ntin @AaronBallman @erichkeane The test on windows platform failed with TLB.TypeWasModifiedSafely(result);. Maybe we shouldn't change LastTy of TLB since we just transform EquivalentType using AuxiliaryTLB and haven't touched TLB.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tested address-spaces.cpp on linux and TLast == LastTy assert also failed. Don't know why the test on linux platform passed.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, I was thinking we didn't need to use AuxiliaryTLB and could instead call TypeWasModifiedSafely but it seems like we need the code as you originally had it (using AuxiliaryTLB but not calling TypeWasModifiedSafely). Sorry for the run-around!

@jcsxky jcsxky force-pushed the fix_crash_attribute_transform branch from 55b433e to 7632f63 Compare January 18, 2024 09:21
Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

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

LGTM but please wait in case @erichkeane has final thoughts.

Comment on lines +7088 to +7094
TypeLocBuilder AuxiliaryTLB;
AuxiliaryTLB.reserve(TL.getFullDataSize());
Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah, you're right, we do still need to do that dance it seems.

@jcsxky jcsxky force-pushed the fix_crash_attribute_transform branch from 7632f63 to b0fcd3b Compare January 19, 2024 03:40
Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

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

Please be sure to add a release note about the fix to clang/docs/ReleaseNotes.rst.

Comment on lines +7088 to +7094
TypeLocBuilder AuxiliaryTLB;
AuxiliaryTLB.reserve(TL.getFullDataSize());
Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, I was thinking we didn't need to use AuxiliaryTLB and could instead call TypeWasModifiedSafely but it seems like we need the code as you originally had it (using AuxiliaryTLB but not calling TypeWasModifiedSafely). Sorry for the run-around!

Comment on lines 6127 to 6138
auto *RD =
dyn_cast_or_null<CXXRecordDecl>(SemaRef.getCurLexicalContext());
Sema::CXXThisScopeRAII ThisScope(
SemaRef, ThisContext == nullptr && nullptr != RD ? RD : ThisContext,
ThisTypeQuals);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
auto *RD =
dyn_cast_or_null<CXXRecordDecl>(SemaRef.getCurLexicalContext());
Sema::CXXThisScopeRAII ThisScope(
SemaRef, ThisContext == nullptr && nullptr != RD ? RD : ThisContext,
ThisTypeQuals);
auto *RD =
dyn_cast<CXXRecordDecl>(SemaRef.getCurLexicalContext());
Sema::CXXThisScopeRAII ThisScope(
SemaRef, !ThisContext && RD ? RD : ThisContext,
ThisTypeQuals);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Code Fixed and release note has been added.

@jcsxky jcsxky force-pushed the fix_crash_attribute_transform branch 3 times, most recently from 0e74e6c to 2d6a39f Compare January 25, 2024 08:45
@cor3ntin
Copy link
Contributor

There seems to be an issue with the rebasing of the PR.
As we branch clang 18, the new changelog (for 19) being empty is expected

@jcsxky
Copy link
Contributor Author

jcsxky commented Jan 25, 2024

There seems to be an issue with the rebasing of the PR. As we branch clang 18, the new changelog (for 19) being empty is expected

I try to merge this PR and found ReleaseNotes.rst is changed because of clang-19 initialize. I don't know where should I add the release note.

@jcsxky jcsxky force-pushed the fix_crash_attribute_transform branch from 2d6a39f to 707c471 Compare January 26, 2024 06:14
@jcsxky jcsxky force-pushed the fix_crash_attribute_transform branch from 707c471 to 9e7ba80 Compare January 26, 2024 06:16
@jcsxky jcsxky merged commit d9d1ae6 into llvm:main Jan 26, 2024
4 of 5 checks passed
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.

Clang crash when using lifetimebound attribute
5 participants