Skip to content

Commit b6628c2

Browse files
authored
[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.
1 parent c4c54af commit b6628c2

File tree

4 files changed

+81
-5
lines changed

4 files changed

+81
-5
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,8 @@ Bug Fixes to C++ Support
555555
- Fix a crash caused by defined struct in a type alias template when the structure
556556
has fields with dependent type. Fixes (#GH75221).
557557
- Fix the Itanium mangling of lambdas defined in a member of a local class (#GH88906)
558+
- Fixed a crash when trying to evaluate a user-defined ``static_assert`` message whose ``size()``
559+
function returns a large or negative value. Fixes (#GH89407).
558560

559561
Bug Fixes to AST Handling
560562
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@ def err_expr_not_cce : Error<
8787
"call to 'size()'|call to 'data()'}0 is not a constant expression">;
8888
def ext_cce_narrowing : ExtWarn<
8989
"%select{case value|enumerator value|non-type template argument|"
90-
"array size|explicit specifier argument|noexcept specifier argument}0 "
91-
"%select{cannot be narrowed from type %2 to %3|"
92-
"evaluates to %2, which cannot be narrowed to type %3}1">,
90+
"array size|explicit specifier argument|noexcept specifier argument|"
91+
"call to 'size()'|call to 'data()'}0 %select{cannot be narrowed from "
92+
"type %2 to %3|evaluates to %2, which cannot be narrowed to type %3}1">,
9393
InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
9494
def err_ice_not_integral : Error<
9595
"%select{integer|integral}1 constant expression must have "

clang/lib/AST/ExprConstant.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16853,13 +16853,13 @@ bool Expr::EvaluateCharRangeAsString(std::string &Result,
1685316853
if (!::EvaluateInteger(SizeExpression, SizeValue, Info))
1685416854
return false;
1685516855

16856-
int64_t Size = SizeValue.getExtValue();
16856+
uint64_t Size = SizeValue.getZExtValue();
1685716857

1685816858
if (!::EvaluatePointer(PtrExpression, String, Info))
1685916859
return false;
1686016860

1686116861
QualType CharTy = PtrExpression->getType()->getPointeeType();
16862-
for (int64_t I = 0; I < Size; ++I) {
16862+
for (uint64_t I = 0; I < Size; ++I) {
1686316863
APValue Char;
1686416864
if (!handleLValueToRValueConversion(Info, PtrExpression, CharTy, String,
1686516865
Char))

clang/test/SemaCXX/static-assert-cxx26.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,3 +341,77 @@ struct Callable {
341341
} data;
342342
};
343343
static_assert(false, Callable{}); // expected-error {{static assertion failed: hello}}
344+
345+
namespace GH89407 {
346+
struct A {
347+
constexpr __SIZE_TYPE__ size() const { return -1; }
348+
constexpr const char* data() const { return ""; }
349+
};
350+
351+
struct B {
352+
constexpr long long size() const { return 18446744073709551615U; }
353+
constexpr const char* data() const { return ""; }
354+
};
355+
356+
struct C {
357+
constexpr __int128 size() const { return -1; }
358+
constexpr const char* data() const { return ""; }
359+
};
360+
361+
struct D {
362+
constexpr unsigned __int128 size() const { return -1; }
363+
constexpr const char* data() const { return ""; }
364+
};
365+
366+
struct E {
367+
constexpr __SIZE_TYPE__ size() const { return 18446744073709551615U; }
368+
constexpr const char* data() const { return ""; }
369+
};
370+
371+
static_assert(true, A{}); // expected-error {{the message in this static assertion is not a constant expression}}
372+
// expected-note@-1 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
373+
static_assert(true, B{}); // expected-error {{call to 'size()' evaluates to -1, which cannot be narrowed to type 'unsigned long'}}
374+
// expected-error@-1 {{the message in this static assertion is not a constant expression}}
375+
// expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
376+
static_assert(true, C{}); // expected-error {{call to 'size()' evaluates to -1, which cannot be narrowed to type 'unsigned long'}}
377+
// expected-error@-1 {{the message in this static assertion is not a constant expression}}
378+
// expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
379+
static_assert(true, D{}); // expected-error {{call to 'size()' evaluates to 340282366920938463463374607431768211455, which cannot be narrowed to type 'unsigned long'}}
380+
// expected-error@-1 {{the message in this static assertion is not a constant expression}}
381+
// expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
382+
static_assert(true, E{}); // expected-error {{the message in this static assertion is not a constant expression}}
383+
// expected-note@-1 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
384+
385+
static_assert(
386+
false, // expected-error {{static assertion failed}}
387+
A{} // expected-error {{the message in a static assertion must be produced by a constant expression}}
388+
// expected-note@-1 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
389+
);
390+
391+
static_assert(
392+
false, // expected-error {{static assertion failed}}
393+
B{} // expected-error {{call to 'size()' evaluates to -1, which cannot be narrowed to type 'unsigned long'}}
394+
// expected-error@-1 {{the message in a static assertion must be produced by a constant expression}}
395+
// expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
396+
);
397+
398+
static_assert(
399+
false, // expected-error {{static assertion failed}}
400+
C{} // expected-error {{call to 'size()' evaluates to -1, which cannot be narrowed to type 'unsigned long'}}
401+
// expected-error@-1 {{the message in a static assertion must be produced by a constant expression}}
402+
// expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
403+
);
404+
405+
static_assert(
406+
false, // expected-error {{static assertion failed}}
407+
D{} // expected-error {{call to 'size()' evaluates to 340282366920938463463374607431768211455, which cannot be narrowed to type 'unsigned long'}}
408+
// expected-error@-1 {{the message in a static assertion must be produced by a constant expression}}
409+
// expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
410+
);
411+
412+
static_assert(
413+
false, // expected-error {{static assertion failed}}
414+
E{} // expected-error {{the message in a static assertion must be produced by a constant expression}}
415+
// expected-note@-1 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
416+
);
417+
}

0 commit comments

Comments
 (0)