Author: Sirraide Date: 2024-04-22T18:41:36+02:00 New Revision: b6628c24ef017138b8d6eb288e94c141e7c846b0
URL: https://github.com/llvm/llvm-project/commit/b6628c24ef017138b8d6eb288e94c141e7c846b0 DIFF: https://github.com/llvm/llvm-project/commit/b6628c24ef017138b8d6eb288e94c141e7c846b0.diff LOG: [Clang] Fix crash on invalid size in user-defined `static_assert` message (#89420) This addresses two problems observed in #89407 wrt user-defined `static_assert` messages: 1. In `Expr::EvaluateCharRangeAsString`, we were calling `getExtValue()` instead of `getZExtValue()`, which would assert if a negative or very large number was returned from `size()`. 2. If the value could not be converted to `std::size_t`, attempting to diagnose that would crash because `ext_cce_narrowing` was missing two `%select` cases. This fixes #89407. Added: Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/AST/ExprConstant.cpp clang/test/SemaCXX/static-assert-cxx26.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 009531bae8a9de..aea99680c79a0e 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -555,6 +555,8 @@ Bug Fixes to C++ Support - Fix a crash caused by defined struct in a type alias template when the structure has fields with dependent type. Fixes (#GH75221). - Fix the Itanium mangling of lambdas defined in a member of a local class (#GH88906) +- Fixed a crash when trying to evaluate a user-defined ``static_assert`` message whose ``size()`` + function returns a large or negative value. Fixes (#GH89407). Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index a95424862e63f4..63e951daec7477 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -87,9 +87,9 @@ def err_expr_not_cce : Error< "call to 'size()'|call to 'data()'}0 is not a constant expression">; def ext_cce_narrowing : ExtWarn< "%select{case value|enumerator value|non-type template argument|" - "array size|explicit specifier argument|noexcept specifier argument}0 " - "%select{cannot be narrowed from type %2 to %3|" - "evaluates to %2, which cannot be narrowed to type %3}1">, + "array size|explicit specifier argument|noexcept specifier argument|" + "call to 'size()'|call to 'data()'}0 %select{cannot be narrowed from " + "type %2 to %3|evaluates to %2, which cannot be narrowed to type %3}1">, InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure; def err_ice_not_integral : Error< "%select{integer|integral}1 constant expression must have " diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 73ae8d8efb23a2..de3c2a63913e94 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -16853,13 +16853,13 @@ bool Expr::EvaluateCharRangeAsString(std::string &Result, if (!::EvaluateInteger(SizeExpression, SizeValue, Info)) return false; - int64_t Size = SizeValue.getExtValue(); + uint64_t Size = SizeValue.getZExtValue(); if (!::EvaluatePointer(PtrExpression, String, Info)) return false; QualType CharTy = PtrExpression->getType()->getPointeeType(); - for (int64_t I = 0; I < Size; ++I) { + for (uint64_t I = 0; I < Size; ++I) { APValue Char; if (!handleLValueToRValueConversion(Info, PtrExpression, CharTy, String, Char)) diff --git a/clang/test/SemaCXX/static-assert-cxx26.cpp b/clang/test/SemaCXX/static-assert-cxx26.cpp index f4ede74f9214a4..7d896d8b365b74 100644 --- a/clang/test/SemaCXX/static-assert-cxx26.cpp +++ b/clang/test/SemaCXX/static-assert-cxx26.cpp @@ -341,3 +341,77 @@ struct Callable { } data; }; static_assert(false, Callable{}); // expected-error {{static assertion failed: hello}} + +namespace GH89407 { +struct A { + constexpr __SIZE_TYPE__ size() const { return -1; } + constexpr const char* data() const { return ""; } +}; + +struct B { + constexpr long long size() const { return 18446744073709551615U; } + constexpr const char* data() const { return ""; } +}; + +struct C { + constexpr __int128 size() const { return -1; } + constexpr const char* data() const { return ""; } +}; + +struct D { + constexpr unsigned __int128 size() const { return -1; } + constexpr const char* data() const { return ""; } +}; + +struct E { + constexpr __SIZE_TYPE__ size() const { return 18446744073709551615U; } + constexpr const char* data() const { return ""; } +}; + +static_assert(true, A{}); // expected-error {{the message in this static assertion is not a constant expression}} + // expected-note@-1 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}} +static_assert(true, B{}); // expected-error {{call to 'size()' evaluates to -1, which cannot be narrowed to type 'unsigned long'}} + // expected-error@-1 {{the message in this static assertion is not a constant expression}} + // expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}} +static_assert(true, C{}); // expected-error {{call to 'size()' evaluates to -1, which cannot be narrowed to type 'unsigned long'}} + // expected-error@-1 {{the message in this static assertion is not a constant expression}} + // expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}} +static_assert(true, D{}); // expected-error {{call to 'size()' evaluates to 340282366920938463463374607431768211455, which cannot be narrowed to type 'unsigned long'}} + // expected-error@-1 {{the message in this static assertion is not a constant expression}} + // expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}} +static_assert(true, E{}); // expected-error {{the message in this static assertion is not a constant expression}} + // expected-note@-1 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}} + +static_assert( + false, // expected-error {{static assertion failed}} + A{} // expected-error {{the message in a static assertion must be produced by a constant expression}} + // expected-note@-1 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}} +); + +static_assert( + false, // expected-error {{static assertion failed}} + B{} // expected-error {{call to 'size()' evaluates to -1, which cannot be narrowed to type 'unsigned long'}} + // expected-error@-1 {{the message in a static assertion must be produced by a constant expression}} + // expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}} +); + +static_assert( + false, // expected-error {{static assertion failed}} + C{} // expected-error {{call to 'size()' evaluates to -1, which cannot be narrowed to type 'unsigned long'}} + // expected-error@-1 {{the message in a static assertion must be produced by a constant expression}} + // expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}} +); + +static_assert( + false, // expected-error {{static assertion failed}} + D{} // expected-error {{call to 'size()' evaluates to 340282366920938463463374607431768211455, which cannot be narrowed to type 'unsigned long'}} + // expected-error@-1 {{the message in a static assertion must be produced by a constant expression}} + // expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}} +); + +static_assert( + false, // expected-error {{static assertion failed}} + E{} // expected-error {{the message in a static assertion must be produced by a constant expression}} + // expected-note@-1 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}} +); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits