-
Notifications
You must be signed in to change notification settings - Fork 15.6k
[clang] Add support for consteval null terminated strings #173140
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17693,6 +17693,44 @@ void Sema::DiagnoseStaticAssertDetails(const Expr *E) { | |
| } | ||
| } | ||
|
|
||
| template <typename ResultType> | ||
| static bool EvaluateAsNullTerminatedCharBuffer( | ||
| Sema &SemaRef, Expr *Message, ResultType &Result, ASTContext &Ctx, | ||
| Sema::StringEvaluationContext EvalContext, bool ErrorOnInvalidMessage) { | ||
| SourceLocation Loc = Message->getBeginLoc(); | ||
| QualType SizeT = Ctx.getSizeType(); | ||
| QualType ConstCharPtr = Ctx.getPointerType(Ctx.getConstType(Ctx.CharTy)); | ||
| Expr::EvalResult Status; | ||
| SmallVector<PartialDiagnosticAt, 8> Notes; | ||
| Status.Diag = &Notes; | ||
|
|
||
| auto DiagnoseInvalidConstantString = [&]() { | ||
| SemaRef.Diag(Loc, diag::err_user_defined_msg_not_null_terminated_string) | ||
| << EvalContext; | ||
| for (const auto &Note : Notes) | ||
| SemaRef.Diag(Note.first, Note.second); | ||
| return !ErrorOnInvalidMessage; | ||
| }; | ||
| ExprResult EvaluatedData = SemaRef.BuildConvertedConstantExpression( | ||
| Message, ConstCharPtr, CCEKind::StaticAssertNullTerminatedString); | ||
| if (EvaluatedData.isInvalid()) | ||
| return DiagnoseInvalidConstantString(); | ||
|
|
||
| uint64_t Length = 0; | ||
| if (!EvaluatedData.get()->tryEvaluateStrLen(Length, Ctx)) | ||
| return DiagnoseInvalidConstantString(); | ||
|
|
||
| llvm::APInt SizeVal(Ctx.getIntWidth(SizeT), Length); | ||
| Expr *SizeExpr = IntegerLiteral::Create(Ctx, SizeVal, SizeT, Loc); | ||
|
|
||
| bool EvalResult = Message->EvaluateCharRangeAsString( | ||
| Result, SizeExpr, EvaluatedData.get(), Ctx, Status); | ||
| if (!EvalResult || !Notes.empty()) | ||
| return DiagnoseInvalidConstantString(); | ||
| SemaRef.Diag(Loc, diag::ext_consteval_string_constants); | ||
| return true; | ||
|
Comment on lines
+17730
to
+17731
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, you put that here! I would put it in the caller
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if we make evaluating a null terminated expression a flag or mode then we can remove this condition - maybe I should then just make the format string or similar routines use the "evaluate null terminated expressions" flag? it seems like such a change would be a minor change (he says with unfounded optimism) |
||
| } | ||
|
|
||
| template <typename ResultType> | ||
| static bool EvaluateAsStringImpl(Sema &SemaRef, Expr *Message, | ||
| ResultType &Result, ASTContext &Ctx, | ||
|
|
@@ -17726,6 +17764,10 @@ static bool EvaluateAsStringImpl(Sema &SemaRef, Expr *Message, | |
|
|
||
| SourceLocation Loc = Message->getBeginLoc(); | ||
| QualType T = Message->getType().getNonReferenceType(); | ||
| if (T->isPointerType() && T->getPointeeType()->isCharType()) | ||
| return EvaluateAsNullTerminatedCharBuffer( | ||
| SemaRef, Message, Result, Ctx, EvalContext, ErrorOnInvalidMessage); | ||
|
|
||
|
Comment on lines
+17767
to
+17770
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem of doing that here is that it is a non-standard behavior. I think the functionality is best left to format string / ptrauth for now. Which brings the question... how do we test this?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A gross option would be to have a langopt + "enable this" cli flag, but that would imply people be able to rely on being able to do this. |
||
| auto *RD = T->getAsCXXRecordDecl(); | ||
| if (!RD) { | ||
| SemaRef.Diag(Loc, diag::err_user_defined_msg_invalid) << EvalContext; | ||
|
|
||
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.
It is not possible to hit this in the new interpreter prior to this change, the existing code fails to handle out of bounds pointer into a string literal (or presumably any array), or an in bounds offset.
It feels like it should be in a different PR, but because it can't currently be hit it can't be tested?
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.
@tbaederr maybe has ideas on testing it on it's own?
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.
Adding it to this PR is fine IMO.
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.
Actually, this might fix #173175, which got filed just 10 minutes ago.
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.
@tbaederr ah ha - I was trying to find a string function that would actually pass that expression to this code but I couldn't work out the correct way to make the call, I think I was trying to get the crash via the first expression, but huzzah we have a test case - will pull this bit out in a moment