summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSirraide <aeternalmail@gmail.com>2024-04-22 18:41:36 +0200
committerGitHub <noreply@github.com>2024-04-22 18:41:36 +0200
commitb6628c24ef017138b8d6eb288e94c141e7c846b0 (patch)
tree3dd098930683c4800df74d3e34f72607957f5142
parentc4c54af569f7c17bc89ae73c3e5c5c4be0a586b9 (diff)
[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.
-rw-r--r--clang/docs/ReleaseNotes.rst2
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td6
-rw-r--r--clang/lib/AST/ExprConstant.cpp4
-rw-r--r--clang/test/SemaCXX/static-assert-cxx26.cpp74
4 files changed, 81 insertions, 5 deletions
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 009531bae8a9..aea99680c79a 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 a95424862e63..63e951daec74 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 73ae8d8efb23..de3c2a63913e 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 f4ede74f9214..7d896d8b365b 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}}
+);
+}