Skip to content

Commit f555f69

Browse files
martinboehmecopybara-github
authored andcommitted
LSC: Fix null safety issues diagnosed by Clang’s -Wnonnull and -Wnullability.
**Note**: These changes are generated by hand. Review with care. This CL changes the `absl_internal` implementations of `AsciiStrToLower()` / `AsciiStrToUpper()` to allow `src` to be null. This can, in fact, happen if the `string_view` passed to the public API is empty, and the implementations handle it correctly. I have added comments noting that `src` is allowed to be null iff the size is zero. `-Wnonnull` diagnoses cases where a `nullptr` literal is passed to a parameter annotated nonnull, or where `nullptr` is returned from a function whose return type is annotated nonnull. `-Wnullability` diagnoses cases where nullability annotations conflict, for example between the declaration and definition of a function. PiperOrigin-RevId: 673846759 Change-Id: I6cf3490ce13837eba9814156c420598000ecc596
1 parent a1a7086 commit f555f69

File tree

5 files changed

+50
-10
lines changed

5 files changed

+50
-10
lines changed

absl/strings/ascii.cc

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,10 @@ constexpr bool AsciiInAZRange(unsigned char c) {
178178
}
179179

180180
// Force-inline so the compiler won't merge the short and long implementations.
181+
// `src` may be null iff `size` is zero.
181182
template <bool ToUpper>
182183
ABSL_ATTRIBUTE_ALWAYS_INLINE inline constexpr void AsciiStrCaseFoldImpl(
183-
absl::Nonnull<char*> dst, absl::Nonnull<const char*> src, size_t size) {
184+
absl::Nonnull<char*> dst, absl::Nullable<const char*> src, size_t size) {
184185
// The upper- and lowercase versions of ASCII characters differ by only 1 bit.
185186
// When we need to flip the case, we can xor with this bit to achieve the
186187
// desired result. Note that the choice of 'a' and 'A' here is arbitrary. We
@@ -199,28 +200,30 @@ ABSL_ATTRIBUTE_ALWAYS_INLINE inline constexpr void AsciiStrCaseFoldImpl(
199200
constexpr size_t kCaseFoldThreshold = 16;
200201

201202
// No-inline so the compiler won't merge the short and long implementations.
203+
// `src` may be null iff `size` is zero.
202204
template <bool ToUpper>
203205
ABSL_ATTRIBUTE_NOINLINE constexpr void AsciiStrCaseFoldLong(
204-
absl::Nonnull<char*> dst, absl::Nonnull<const char*> src, size_t size) {
206+
absl::Nonnull<char*> dst, absl::Nullable<const char*> src, size_t size) {
205207
ABSL_ASSUME(size >= kCaseFoldThreshold);
206208
AsciiStrCaseFoldImpl<ToUpper>(dst, src, size);
207209
}
208210

209211
// Splitting to short and long strings to allow vectorization decisions
210212
// to be made separately in the long and short cases.
213+
// `src` may be null iff `size` is zero.
211214
template <bool ToUpper>
212215
constexpr void AsciiStrCaseFold(absl::Nonnull<char*> dst,
213-
absl::Nonnull<const char*> src, size_t size) {
216+
absl::Nullable<const char*> src, size_t size) {
214217
size < kCaseFoldThreshold ? AsciiStrCaseFoldImpl<ToUpper>(dst, src, size)
215218
: AsciiStrCaseFoldLong<ToUpper>(dst, src, size);
216219
}
217220

218-
void AsciiStrToLower(absl::Nonnull<char*> dst, absl::Nonnull<const char*> src,
221+
void AsciiStrToLower(absl::Nonnull<char*> dst, absl::Nullable<const char*> src,
219222
size_t n) {
220223
return AsciiStrCaseFold<false>(dst, src, n);
221224
}
222225

223-
void AsciiStrToUpper(absl::Nonnull<char*> dst, absl::Nonnull<const char*> src,
226+
void AsciiStrToUpper(absl::Nonnull<char*> dst, absl::Nullable<const char*> src,
224227
size_t n) {
225228
return AsciiStrCaseFold<true>(dst, src, n);
226229
}

absl/strings/ascii.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,10 @@ ABSL_DLL extern const char kToUpper[256];
7676
// Declaration for the array of characters to lower-case characters.
7777
ABSL_DLL extern const char kToLower[256];
7878

79-
void AsciiStrToLower(absl::Nonnull<char*> dst, absl::Nonnull<const char*> src,
79+
void AsciiStrToLower(absl::Nonnull<char*> dst, absl::Nullable<const char*> src,
8080
size_t n);
8181

82-
void AsciiStrToUpper(absl::Nonnull<char*> dst, absl::Nonnull<const char*> src,
82+
void AsciiStrToUpper(absl::Nonnull<char*> dst, absl::Nullable<const char*> src,
8383
size_t n);
8484

8585
} // namespace ascii_internal

absl/strings/ascii_test.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,10 @@ TEST(AsciiStrTo, Lower) {
200200
EXPECT_EQ("abcdefghijklmnopqrstuvwxyz1!a", absl::AsciiStrToLower(long_str));
201201
EXPECT_EQ("pqrstu", absl::AsciiStrToLower(fun()));
202202

203+
// An empty `string_view` specifically exercises the case where a null data
204+
// pointer is passed to internal functions.
205+
EXPECT_EQ("", absl::AsciiStrToLower(absl::string_view()));
206+
203207
absl::AsciiStrToLower(&mutable_str);
204208
EXPECT_EQ("_`?@[{amnopqrstuvwxyz", mutable_str);
205209

@@ -223,6 +227,10 @@ TEST(AsciiStrTo, Upper) {
223227
EXPECT_EQ("ABCDEFGHIJKLMNOPQRSTUVWXYZ1!A", absl::AsciiStrToUpper(long_str));
224228
EXPECT_EQ("PQRSTU", absl::AsciiStrToUpper(fun()));
225229

230+
// An empty `string_view` specifically exercises the case where a null data
231+
// pointer is passed to internal functions.
232+
EXPECT_EQ("", absl::AsciiStrToUpper(absl::string_view()));
233+
226234
char mutable_buf[] = "Mutable";
227235
std::transform(mutable_buf, mutable_buf + strlen(mutable_buf),
228236
mutable_buf, absl::ascii_toupper);

absl/strings/str_format_test.cc

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,13 @@ TEST_F(FormatEntryPointTest, SNPrintF) {
516516
EXPECT_EQ(result, 17);
517517
EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
518518

519-
result = SNPrintF(nullptr, 0, "Just checking the %s of the output.", "size");
519+
// The `output` parameter is annotated nonnull, but we want to test that
520+
// it is never written to if the size is zero.
521+
// Use a variable instead of passing nullptr directly to avoid a `-Wnonnull`
522+
// warning.
523+
char* null_output = nullptr;
524+
result =
525+
SNPrintF(null_output, 0, "Just checking the %s of the output.", "size");
520526
EXPECT_EQ(result, 37);
521527
}
522528

@@ -545,7 +551,13 @@ TEST_F(FormatEntryPointTest, SNPrintFWithV) {
545551

546552
std::string size = "size";
547553

548-
result = SNPrintF(nullptr, 0, "Just checking the %v of the output.", size);
554+
// The `output` parameter is annotated nonnull, but we want to test that
555+
// it is never written to if the size is zero.
556+
// Use a variable instead of passing nullptr directly to avoid a `-Wnonnull`
557+
// warning.
558+
char* null_output = nullptr;
559+
result =
560+
SNPrintF(null_output, 0, "Just checking the %v of the output.", size);
549561
EXPECT_EQ(result, 37);
550562
}
551563

absl/strings/string_view_test.cc

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -894,7 +894,11 @@ TEST(StringViewTest, NULLInput) {
894894
EXPECT_EQ(s.size(), 0u);
895895

896896
#ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
897-
s = absl::string_view(nullptr);
897+
// The `str` parameter is annotated nonnull, but we want to test the defensive
898+
// null check. Use a variable instead of passing nullptr directly to avoid a
899+
// `-Wnonnull` warning.
900+
char* null_str = nullptr;
901+
s = absl::string_view(null_str);
898902
EXPECT_EQ(s.data(), nullptr);
899903
EXPECT_EQ(s.size(), 0u);
900904

@@ -1076,8 +1080,21 @@ TEST(StringViewTest, ConstexprNullSafeStringView) {
10761080

10771081
TEST(StringViewTest, ConstexprCompiles) {
10781082
constexpr absl::string_view sp;
1083+
// With `-Wnonnull` turned on, there is no way to test the defensive null
1084+
// check in the `string_view(const char*)` constructor in a constexpr context,
1085+
// as the argument needs to be constexpr. The compiler will therefore always
1086+
// know at compile time that the argument is nullptr and complain because the
1087+
// parameter is annotated nonnull. We hence turn the warning off for this
1088+
// test.
1089+
#if defined(__clang__)
1090+
#pragma clang diagnostic push
1091+
#pragma clang diagnostic ignored "-Wnonnull"
1092+
#endif
10791093
#ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
10801094
constexpr absl::string_view cstr(nullptr);
1095+
#endif
1096+
#if defined(__clang__)
1097+
#pragma clang diagnostic pop
10811098
#endif
10821099
constexpr absl::string_view cstr_len("cstr", 4);
10831100

0 commit comments

Comments
 (0)