Skip to content

Commit 5825b32

Browse files
committed
[-Wunterminated-string-initialization] Handle C string literals ending with explicit '\0'
In C, a char array needs no "nonstring" attribute, if its initializer is a string literal that 1) explicitly ends with '\0' and 2) fits in the array after a possible truncation. For example `char a[4] = "ABC\0"; // fine, needs no "nonstring" attr` rdar://152506883
1 parent 591678b commit 5825b32

File tree

2 files changed

+33
-0
lines changed

2 files changed

+33
-0
lines changed

clang/lib/Sema/SemaInit.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,11 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
260260
diag::ext_initializer_string_for_char_array_too_long)
261261
<< Str->getSourceRange();
262262
else if (StrLength - 1 == ArrayLen) {
263+
// If the string literal is null-terminated explicitly, e.g., `char a[4] =
264+
// "ABC\0"`, there should be no warn:
265+
if (const auto *SL = dyn_cast<StringLiteral>(Str->IgnoreParens()))
266+
if (SL->isOrdinary() && SL->getBytes().back() == 0)
267+
return;
263268
// If the entity being initialized has the nonstring attribute, then
264269
// silence the "missing nonstring" diagnostic. If there's no entity,
265270
// check whether we're initializing an array of arrays; if so, walk the
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify -Wunterminated-string-initialization %s -x c
2+
// RUN: %clang_cc1 -fsyntax-only -verify -Wunterminated-string-initialization %s -x c++
3+
4+
5+
// In C, the following examples are fine:
6+
#if __cplusplus
7+
char foo[3] = "fo\0"; // expected-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
8+
9+
struct S {
10+
char buf[3];
11+
char fub[3];
12+
} s = { "ba\0", "bo\0" }; // expected-error 2{{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
13+
14+
signed char scfoo[3] = "fo\0"; // expected-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
15+
unsigned char ucfoo[3] = "fo\0"; // expected-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
16+
17+
#else
18+
//expected-no-diagnostics
19+
char foo[3] = "fo\0";
20+
21+
struct S {
22+
char buf[3];
23+
char fub[3];
24+
} s = { "ba\0", "bo\0" };
25+
26+
signed char scfoo[3] = "fo\0";
27+
unsigned char ucfoo[3] = "fo\0";
28+
#endif

0 commit comments

Comments
 (0)