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] fix sema init crashing on initialization sequences #98102

Merged
merged 2 commits into from
Jul 10, 2024

Conversation

yuxuanchen1997
Copy link
Contributor

@yuxuanchen1997 yuxuanchen1997 commented Jul 9, 2024

We ran into a FE crash and root caused to ER.get() on line 5584 here being nullptr. I think this is a result of not checking if ER here is invalid.

Example of crash-on-valid C++ https://gist.github.com/yuxuanchen1997/576dce964666f0f8713fccacf5847138

Note that this crash happens only with -std=c++20.

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

llvmbot commented Jul 9, 2024

@llvm/pr-subscribers-clang

Author: Yuxuan Chen (yuxuanchen1997)

Changes

We ran into a FE crash and root caused to ER.get() on line 5584 here being nullptr. I think this is a result of not checking if ER here is invalid.

We have been using automated reduction tools (like CReduce) for a while and it is not performing well and would like to ask upstream opinions on whether this condition here is handled correctly. Preferably with help to write a small, well contained crash-on-valid test case.

I do have a crash-on-invalid test here, would really appreciate any pointers.


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

1 Files Affected:

  • (modified) clang/lib/Sema/SemaInit.cpp (+4)
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 41753a1661ace..80286302e9b9d 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -5576,6 +5576,10 @@ static void TryOrBuildParenListInitialization(
       ExprResult ER;
       ER = IS.Perform(S, SubEntity, SubKind,
                       Arg ? MultiExprArg(Arg) : std::nullopt);
+
+      if (ER.IsInvalid())
+        return false;
+
       if (InitExpr)
         *InitExpr = ER.get();
       else


if (ER.IsInvalid())
return false;

if (InitExpr)
*InitExpr = ER.get();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

ER.get() is null if we don't apply this fix.

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.

Thank you!

You should also add test coverage (clang/test/SemaCXX) for the changes and a release note (clang/docs/ReleaseNotes.rst).

@@ -5576,6 +5576,10 @@ static void TryOrBuildParenListInitialization(
ExprResult ER;
ER = IS.Perform(S, SubEntity, SubKind,
Arg ? MultiExprArg(Arg) : std::nullopt);

if (ER.isInvalid())
Copy link
Collaborator

Choose a reason for hiding this comment

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

Under what circumstances does IS.Failed() return false above but when we perform the initialization we get a null expression back? That seems strange to me -- I would have naively expected Failed() to return true in such a case. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If you look at InitializationSequence::Perform (this function is 1000 lines long), it first checks Failed() then proceed to build a whole bunch of things. There are a couple of places it returned ExprError. I think it's possible to still be invalid after !Failed().

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 are correct, sorry! I see now that the common code pattern is to check isInvalid() on the returned result.

@cor3ntin
Copy link
Contributor

cor3ntin commented Jul 9, 2024

@Endilll you are able to reduce that further?

@dcci
Copy link
Member

dcci commented Jul 9, 2024

You should also add test coverage (clang/test/SemaCXX) for the changes and a release note (clang/docs/ReleaseNotes.rst).

@AaronBallman -- are you OK with a crash-on-invalid (the one in first post)? The original example we had crashed on valid code, but reducing a 35MB file with a lot of SFINAE is taking weeks with c-reduce.
Thanks for your review :)

@AaronBallman
Copy link
Collaborator

You should also add test coverage (clang/test/SemaCXX) for the changes and a release note (clang/docs/ReleaseNotes.rst).

@AaronBallman -- are you OK with a crash-on-invalid (the one in first post)? The original example we had crashed on valid code, but reducing a 35MB file with a lot of SFINAE is taking weeks with c-reduce. Thanks for your review :)

Ideally we'd have test coverage for both the crash-on-invalid and crash-on-valid code, if possible. If we can't get a reduction to a crash-on-valid case, then crash-on-invalid that also fixes the valid case would be okay. But we could perhaps help reduce the crash-on-valid code if you can share it.

@dcci
Copy link
Member

dcci commented Jul 9, 2024

You should also add test coverage (clang/test/SemaCXX) for the changes and a release note (clang/docs/ReleaseNotes.rst).

@AaronBallman -- are you OK with a crash-on-invalid (the one in first post)? The original example we had crashed on valid code, but reducing a 35MB file with a lot of SFINAE is taking weeks with c-reduce. Thanks for your review :)

Ideally we'd have test coverage for both the crash-on-invalid and crash-on-valid code, if possible. If we can't get a reduction to a crash-on-valid case, then crash-on-invalid that also fixes the valid case would be okay. But we could perhaps help reduce the crash-on-valid code if you can share it.

Thank you Aaron. Unfortunately this is from some Meta internal codebase, so it's hard to share. I'm trying to reduce myself.

@yuxuanchen1997
Copy link
Contributor Author

yuxuanchen1997 commented Jul 9, 2024

@AaronBallman I have good news. I was able to manually write a well-formed C++ file that crashes. https://gist.github.com/yuxuanchen1997/576dce964666f0f8713fccacf5847138

And I am able to validate that the fix I proposed here does fix the problem. I am going to add this test to the patch and figure out why we were crashing in the first place.

@yuxuanchen1997 yuxuanchen1997 force-pushed the fix-sema-init-crash branch 5 times, most recently from f12bfc7 to 3c5b72d Compare July 10, 2024 04:07
@Endilll
Copy link
Contributor

Endilll commented Jul 10, 2024

@Endilll you are able to reduce that further?

I don't see the original reproducer anywhere. Snippet in the description is already reduced (and got quite damaged in the process). I can reduce it myself if someone points me out to the original reproducer.

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.

The changes LGTM, but please add a release note to clang/docs/ReleaseNotes.rst so users know about the fix.

@@ -5576,6 +5576,10 @@ static void TryOrBuildParenListInitialization(
ExprResult ER;
ER = IS.Perform(S, SubEntity, SubKind,
Arg ? MultiExprArg(Arg) : std::nullopt);

if (ER.isInvalid())
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 are correct, sorry! I see now that the common code pattern is to check isInvalid() on the returned result.

@yuxuanchen1997 yuxuanchen1997 changed the title [clang] fix sema init crash for not checking a ExprResult [clang] fix sema init crashing on initialization sequences Jul 10, 2024
@yuxuanchen1997
Copy link
Contributor Author

The changes LGTM, but please add a release note to clang/docs/ReleaseNotes.rst so users know about the fix.

Added. Thanks.

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, thank you for the fix!

@yuxuanchen1997 yuxuanchen1997 merged commit 6f13c71 into llvm:main Jul 10, 2024
6 of 7 checks passed
@yuxuanchen1997 yuxuanchen1997 deleted the fix-sema-init-crash branch July 10, 2024 19:01
aaryanshukla pushed a commit to aaryanshukla/llvm-project that referenced this pull request Jul 14, 2024
We ran into a FE crash and root caused to `ER.get()` on line 5584 here
being nullptr. I think this is a result of not checking if ER here is
invalid.

Example of crash-on-valid C++
https://gist.github.com/yuxuanchen1997/576dce964666f0f8713fccacf5847138

Note that this crash happens only with `-std=c++20`.
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.

None yet

6 participants