https://github.com/hazohelet updated https://github.com/llvm/llvm-project/pull/65969
>From 5ee1a4f83c69b5e2910ea883dca7f0fa2c1a4bd3 Mon Sep 17 00:00:00 2001 From: Takuya Shimizu <shimizu2...@gmail.com> Date: Wed, 13 Sep 2023 17:43:11 +0900 Subject: [PATCH 1/4] [clang][Diagnostics] Separate Wformat-overflow and Wformat-truncation from Wfortify-source Newly introduces `Wformat-overflow` and `Wformat-truncation` and imports the existing warning from `Wfortify-source` that correspond to GCC's counterpart so that they can be disabled separately from `Wfortify-source`. --- clang/docs/ReleaseNotes.rst | 5 +- .../clang/Basic/DiagnosticSemaKinds.td | 4 +- clang/lib/Sema/SemaChecking.cpp | 12 +- .../Sema/warn-format-overflow-truncation.c | 153 ++++++++++++++++++ clang/test/Sema/warn-fortify-source.c | 14 +- 5 files changed, 171 insertions(+), 17 deletions(-) create mode 100644 clang/test/Sema/warn-format-overflow-truncation.c diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 3cdad2f7b9f0e5a..628253c730cd1e0 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -160,9 +160,12 @@ Improvements to Clang's diagnostics - Clang constexpr evaluator now diagnoses compound assignment operators against uninitialized variables as a read of uninitialized object. (`#51536 <https://github.com/llvm/llvm-project/issues/51536>`_) -- Clang's ``-Wfortify-source`` now diagnoses ``snprintf`` call that is known to +- Clang's ``-Wformat-truncation`` now diagnoses ``snprintf`` call that is known to result in string truncation. (`#64871: <https://github.com/llvm/llvm-project/issues/64871>`_). + Existing warnings that similarly warn about the overflow in ``sprintf`` + now falls under its own warning group ```-Wformat-overflow`` so that it can + be disabled separately from ``Wfortify-source``. Also clang no longer emits false positive warnings about the output length of ``%g`` format specifier and about ``%o, %x, %X`` with ``#`` flag. - Clang now emits ``-Wcast-qual`` for functional-style cast expressions. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 0ac4df8edb242f6..7f708a5267e0052 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -857,12 +857,12 @@ def warn_fortify_strlen_overflow: Warning< def warn_fortify_source_format_overflow : Warning< "'%0' will always overflow; destination buffer has size %1," " but format string expands to at least %2">, - InGroup<FortifySource>; + InGroup<DiagGroup<"format-overflow">>; def warn_fortify_source_format_truncation: Warning< "'%0' will always be truncated; specified size is %1," " but format string expands to at least %2">, - InGroup<FortifySource>; + InGroup<DiagGroup<"format-truncation">>; def warn_fortify_scanf_overflow : Warning< "'%0' may overflow; destination buffer in argument %1 has size " diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index fad70223362eddd..8260e72bd99e839 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1350,10 +1350,14 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, llvm::APSInt::getUnsigned(H.getSizeLowerBound()) .extOrTrunc(SizeTypeWidth); if (FormatSize > *SourceSize && *SourceSize != 0) { - DiagID = diag::warn_fortify_source_format_truncation; - DestinationSize = SourceSize; - SourceSize = FormatSize; - break; + SmallString<16> SpecifiedSizeStr; + SmallString<16> FormatSizeStr; + SourceSize->toString(SpecifiedSizeStr, /*Radix=*/10); + FormatSize.toString(FormatSizeStr, /*Radix=*/10); + DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall, + PDiag(diag::warn_fortify_source_format_truncation) + << GetFunctionName() << SpecifiedSizeStr + << FormatSizeStr); } } } diff --git a/clang/test/Sema/warn-format-overflow-truncation.c b/clang/test/Sema/warn-format-overflow-truncation.c new file mode 100644 index 000000000000000..dada1f9355afe07 --- /dev/null +++ b/clang/test/Sema/warn-format-overflow-truncation.c @@ -0,0 +1,153 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 %s -verify +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 %s -verify -DUSE_BUILTINS +// RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 %s -verify +// RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 %s -verify -DUSE_BUILTINS +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 -Wno-format-truncation -Wno-format-overflow %s -verify=off +// RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 -Wno-format-truncation -Wno-format-overflow %s -verify=off + +typedef unsigned long size_t; + +#ifdef __cplusplus +extern "C" { +#endif + +extern int sprintf(char *str, const char *format, ...); + +#ifdef __cplusplus +} +#endif + +void call_snprintf(double d, int n) { + char buf[10]; + __builtin_snprintf(buf, 10, "merp"); + __builtin_snprintf(buf, 11, "merp"); // expected-warning {{'snprintf' size argument is too large; destination buffer has size 10, but size argument is 11}} \ + // off-warning {{size argument is too large}} + __builtin_snprintf(buf, 12, "%#12x", n); // expected-warning {{'snprintf' will always be truncated; specified size is 12, but format string expands to at least 13}} \ + // expected-warning {{'snprintf' size argument is too large; destination buffer has size 10, but size argument is 12}} \ + // off-warning {{'snprintf' size argument is too large; destination buffer has size 10, but size argument is 12}} \ + __builtin_snprintf(buf, 0, "merp"); + __builtin_snprintf(buf, 3, "merp"); // expected-warning {{'snprintf' will always be truncated; specified size is 3, but format string expands to at least 5}} + __builtin_snprintf(buf, 4, "merp"); // expected-warning {{'snprintf' will always be truncated; specified size is 4, but format string expands to at least 5}} + __builtin_snprintf(buf, 5, "merp"); + __builtin_snprintf(buf, 1, "%.1000g", d); // expected-warning {{'snprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} + __builtin_snprintf(buf, 5, "%.1000g", d); + __builtin_snprintf(buf, 5, "%.1000G", d); + __builtin_snprintf(buf, 10, " %#08x", n); + __builtin_snprintf(buf, 2, "%#x", n); + __builtin_snprintf(buf, 2, "%#X", n); + __builtin_snprintf(buf, 2, "%#o", n); + __builtin_snprintf(buf, 1, "%#x", n); // expected-warning {{'snprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} + __builtin_snprintf(buf, 1, "%#X", n); // expected-warning {{'snprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} + __builtin_snprintf(buf, 1, "%#o", n); // expected-warning {{'snprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} +} + +void call_vsnprintf(void) { + char buf[10]; + __builtin_va_list list; + __builtin_vsnprintf(buf, 10, "merp", list); + __builtin_vsnprintf(buf, 11, "merp", list); // expected-warning {{'vsnprintf' size argument is too large; destination buffer has size 10, but size argument is 11}} \ + // off-warning {{size argument is too large}} + __builtin_vsnprintf(buf, 0, "merp", list); + __builtin_vsnprintf(buf, 3, "merp", list); // expected-warning {{'vsnprintf' will always be truncated; specified size is 3, but format string expands to at least 5}} + __builtin_vsnprintf(buf, 4, "merp", list); // expected-warning {{'vsnprintf' will always be truncated; specified size is 4, but format string expands to at least 5}} + __builtin_vsnprintf(buf, 5, "merp", list); + __builtin_vsnprintf(buf, 1, "%.1000g", list); // expected-warning {{'vsnprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} + __builtin_vsnprintf(buf, 5, "%.1000g", list); + __builtin_vsnprintf(buf, 5, "%.1000G", list); + __builtin_vsnprintf(buf, 10, " %#08x", list); + __builtin_vsnprintf(buf, 2, "%#x", list); + __builtin_vsnprintf(buf, 2, "%#X", list); + __builtin_vsnprintf(buf, 2, "%#o", list); + __builtin_vsnprintf(buf, 1, "%#x", list); // expected-warning {{'vsnprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} + __builtin_vsnprintf(buf, 1, "%#X", list); // expected-warning {{'vsnprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} + __builtin_vsnprintf(buf, 1, "%#o", list); // expected-warning {{'vsnprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} +} + +void call_sprintf_chk(char *buf) { + __builtin___sprintf_chk(buf, 1, 6, "hell\n"); + __builtin___sprintf_chk(buf, 1, 5, "hell\n"); // expected-warning {{'sprintf' will always overflow; destination buffer has size 5, but format string expands to at least 6}} + __builtin___sprintf_chk(buf, 1, 6, "hell\0 boy"); // expected-warning {{format string contains '\0' within the string body}} \ + // off-warning {{format string contains '\0' within the string body}} + __builtin___sprintf_chk(buf, 1, 2, "hell\0 boy"); // expected-warning {{format string contains '\0' within the string body}} \ + // off-warning {{format string contains '\0' within the string body}} \ + // expected-warning {{'sprintf' will always overflow; destination buffer has size 2, but format string expands to at least 5}} + __builtin___sprintf_chk(buf, 1, 6, "hello"); + __builtin___sprintf_chk(buf, 1, 5, "hello"); // expected-warning {{'sprintf' will always overflow; destination buffer has size 5, but format string expands to at least 6}} + __builtin___sprintf_chk(buf, 1, 2, "%c", '9'); + __builtin___sprintf_chk(buf, 1, 1, "%c", '9'); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 2, "%d", 9); + __builtin___sprintf_chk(buf, 1, 1, "%d", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 2, "%i", 9); + __builtin___sprintf_chk(buf, 1, 1, "%i", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 2, "%o", 9); + __builtin___sprintf_chk(buf, 1, 1, "%o", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 2, "%u", 9); + __builtin___sprintf_chk(buf, 1, 1, "%u", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 2, "%x", 9); + __builtin___sprintf_chk(buf, 1, 1, "%x", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 2, "%X", 9); + __builtin___sprintf_chk(buf, 1, 1, "%X", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 2, "%hhd", (char)9); + __builtin___sprintf_chk(buf, 1, 1, "%hhd", (char)9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 2, "%hd", (short)9); + __builtin___sprintf_chk(buf, 1, 1, "%hd", (short)9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 2, "%ld", 9l); + __builtin___sprintf_chk(buf, 1, 1, "%ld", 9l); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 2, "%lld", 9ll); + __builtin___sprintf_chk(buf, 1, 1, "%lld", 9ll); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 2, "%%"); + __builtin___sprintf_chk(buf, 1, 1, "%%"); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 4, "%#x", 9); + __builtin___sprintf_chk(buf, 1, 3, "%#x", 9); + __builtin___sprintf_chk(buf, 1, 4, "%p", (void *)9); + __builtin___sprintf_chk(buf, 1, 3, "%p", (void *)9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 3, but format string expands to at least 4}} + __builtin___sprintf_chk(buf, 1, 3, "%+d", 9); + __builtin___sprintf_chk(buf, 1, 2, "%+d", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 2, but format string expands to at least 3}} + __builtin___sprintf_chk(buf, 1, 3, "% i", 9); + __builtin___sprintf_chk(buf, 1, 2, "% i", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 2, but format string expands to at least 3}} + __builtin___sprintf_chk(buf, 1, 6, "%5d", 9); + __builtin___sprintf_chk(buf, 1, 5, "%5d", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 5, but format string expands to at least 6}} + __builtin___sprintf_chk(buf, 1, 9, "%f", 9.f); + __builtin___sprintf_chk(buf, 1, 8, "%f", 9.f); // expected-warning {{'sprintf' will always overflow; destination buffer has size 8, but format string expands to at least 9}} + __builtin___sprintf_chk(buf, 1, 9, "%Lf", (long double)9.); + __builtin___sprintf_chk(buf, 1, 8, "%Lf", (long double)9.); // expected-warning {{'sprintf' will always overflow; destination buffer has size 8, but format string expands to at least 9}} + __builtin___sprintf_chk(buf, 1, 10, "%+f", 9.f); + __builtin___sprintf_chk(buf, 1, 9, "%+f", 9.f); // expected-warning {{'sprintf' will always overflow; destination buffer has size 9, but format string expands to at least 10}} + __builtin___sprintf_chk(buf, 1, 12, "%e", 9.f); + __builtin___sprintf_chk(buf, 1, 11, "%e", 9.f); // expected-warning {{'sprintf' will always overflow; destination buffer has size 11, but format string expands to at least 12}} +} + +void call_sprintf(void) { + char buf[6]; + sprintf(buf, "hell\0 boy"); // expected-warning {{format string contains '\0' within the string body}} \ + // off-warning {{format string contains '\0' within the string body}} + sprintf(buf, "hello b\0y"); // expected-warning {{format string contains '\0' within the string body}} \ + // off-warning {{format string contains '\0' within the string body}} \ + // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 8}} + sprintf(buf, "hello"); + sprintf(buf, "hello!"); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "1234%%"); + sprintf(buf, "12345%%"); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "1234%c", '9'); + sprintf(buf, "12345%c", '9'); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "1234%d", 9); + sprintf(buf, "12345%d", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "1234%lld", 9ll); + sprintf(buf, "12345%lld", 9ll); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "12%#x", 9); + sprintf(buf, "123%#x", 9); + sprintf(buf, "12%p", (void *)9); + sprintf(buf, "123%p", (void *)9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "123%+d", 9); + sprintf(buf, "1234%+d", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "123% i", 9); + sprintf(buf, "1234% i", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "%5d", 9); + sprintf(buf, "1%5d", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "%.3f", 9.f); + sprintf(buf, "5%.3f", 9.f); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "%+.2f", 9.f); + sprintf(buf, "%+.3f", 9.f); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "%.0e", 9.f); + sprintf(buf, "5%.1e", 9.f); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 8}} +} diff --git a/clang/test/Sema/warn-fortify-source.c b/clang/test/Sema/warn-fortify-source.c index de6171af8c14524..a12460b963cd00f 100644 --- a/clang/test/Sema/warn-fortify-source.c +++ b/clang/test/Sema/warn-fortify-source.c @@ -2,8 +2,6 @@ // RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 %s -verify -DUSE_BUILTINS // RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 %s -verify // RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 %s -verify -DUSE_BUILTINS -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 -Wno-fortify-source %s -verify=nofortify -// RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 -Wno-fortify-source %s -verify=nofortify typedef unsigned long size_t; @@ -129,11 +127,9 @@ void call_vsnprintf(void) { void call_sprintf_chk(char *buf) { __builtin___sprintf_chk(buf, 1, 6, "hell\n"); __builtin___sprintf_chk(buf, 1, 5, "hell\n"); // expected-warning {{'sprintf' will always overflow; destination buffer has size 5, but format string expands to at least 6}} - __builtin___sprintf_chk(buf, 1, 6, "hell\0 boy"); // expected-warning {{format string contains '\0' within the string body}} \ - // nofortify-warning {{format string contains '\0' within the string body}} + __builtin___sprintf_chk(buf, 1, 6, "hell\0 boy"); // expected-warning {{format string contains '\0' within the string body}} __builtin___sprintf_chk(buf, 1, 2, "hell\0 boy"); // expected-warning {{format string contains '\0' within the string body}} \ - // nofortify-warning {{format string contains '\0' within the string body}} - // expected-warning@-2 {{'sprintf' will always overflow; destination buffer has size 2, but format string expands to at least 5}} + // expected-warning {{'sprintf' will always overflow; destination buffer has size 2, but format string expands to at least 5}} __builtin___sprintf_chk(buf, 1, 6, "hello"); __builtin___sprintf_chk(buf, 1, 5, "hello"); // expected-warning {{'sprintf' will always overflow; destination buffer has size 5, but format string expands to at least 6}} __builtin___sprintf_chk(buf, 1, 2, "%c", '9'); @@ -182,11 +178,9 @@ void call_sprintf_chk(char *buf) { void call_sprintf(void) { char buf[6]; - sprintf(buf, "hell\0 boy"); // expected-warning {{format string contains '\0' within the string body}} \ - // nofortify-warning {{format string contains '\0' within the string body}} + sprintf(buf, "hell\0 boy"); // expected-warning {{format string contains '\0' within the string body}} sprintf(buf, "hello b\0y"); // expected-warning {{format string contains '\0' within the string body}} \ - // nofortify-warning {{format string contains '\0' within the string body}} - // expected-warning@-2 {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 8}} + // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 8}} sprintf(buf, "hello"); sprintf(buf, "hello!"); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} sprintf(buf, "1234%%"); >From 59ff7cd5b4291baee7637cf6f51bc49457aab689 Mon Sep 17 00:00:00 2001 From: Takuya Shimizu <shimizu2...@gmail.com> Date: Wed, 13 Sep 2023 18:17:26 +0900 Subject: [PATCH 2/4] Introduce `-Wformat-overflow-non-kprintf` and `-Wformat-truncation-non-kprintf` for format string that contains `%p` --- clang/docs/ReleaseNotes.rst | 7 + clang/include/clang/Basic/DiagnosticGroups.td | 8 +- .../clang/Basic/DiagnosticSemaKinds.td | 26 +++- clang/lib/Sema/SemaChecking.cpp | 17 ++- clang/test/Misc/warning-wall.c | 4 + .../Sema/warn-format-overflow-truncation.c | 139 +++++++++--------- 6 files changed, 124 insertions(+), 77 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 628253c730cd1e0..5c2779009ec6a18 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -166,6 +166,13 @@ Improvements to Clang's diagnostics Existing warnings that similarly warn about the overflow in ``sprintf`` now falls under its own warning group ```-Wformat-overflow`` so that it can be disabled separately from ``Wfortify-source``. + These two new warning groups have subgroups ``-Wformat-truncation-non-kprintf`` + and ``-Wformat-overflow-non-kprintf``, respectively. These subgroups are used when + the format string contains ``%p`` format specifier. + Because Linux kernel's codebase has format extensions for ``%p``, kernel developers + are encouraged to disable these two subgroups by setting ``-Wno-format-truncation-non-kprintf`` + and ``-Wno-format-truncation-non-kprintf`` in order to avoid false positives on + the kernel codebase. Also clang no longer emits false positive warnings about the output length of ``%g`` format specifier and about ``%o, %x, %X`` with ``#`` flag. - Clang now emits ``-Wcast-qual`` for functional-style cast expressions. diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 00c458fb23e73e2..162eff37cc910c0 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -961,10 +961,16 @@ def FormatNonStandard : DiagGroup<"format-non-iso">; def FormatY2K : DiagGroup<"format-y2k">; def FormatPedantic : DiagGroup<"format-pedantic">; def FormatTypeConfusion : DiagGroup<"format-type-confusion">; + +def FormatOverflowNonKprintf: DiagGroup<"format-overflow-non-kprintf">; +def FormatOverflow: DiagGroup<"format-overflow", [FormatOverflowNonKprintf]>; +def FormatTruncationNonKprintf: DiagGroup<"format-truncation-non-kprintf">; +def FormatTruncation: DiagGroup<"format-truncation", [FormatTruncationNonKprintf]>; + def Format : DiagGroup<"format", [FormatExtraArgs, FormatZeroLength, NonNull, FormatSecurity, FormatY2K, FormatInvalidSpecifier, - FormatInsufficientArgs]>, + FormatInsufficientArgs, FormatOverflow, FormatTruncation]>, DiagCategory<"Format String Issue">; def FormatNonLiteral : DiagGroup<"format-nonliteral">; def Format2 : DiagGroup<"format=2", diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 7f708a5267e0052..fccbee1bc3b73f2 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -854,15 +854,29 @@ def warn_fortify_strlen_overflow: Warning< " but the source string has length %2 (including NUL byte)">, InGroup<FortifySource>; -def warn_fortify_source_format_overflow : Warning< +def subst_format_overflow : TextSubstitution< "'%0' will always overflow; destination buffer has size %1," - " but format string expands to at least %2">, - InGroup<DiagGroup<"format-overflow">>; + " but format string expands to at least %2">; -def warn_fortify_source_format_truncation: Warning< +def warn_format_overflow : Warning< + "%sub{subst_format_overflow}0,1,2">, + InGroup<FormatOverflow>; + +def warn_format_overflow_non_kprintf : Warning< + "%sub{subst_format_overflow}0,1,2">, + InGroup<FormatOverflowNonKprintf>; + +def subst_format_truncation: TextSubstitution< "'%0' will always be truncated; specified size is %1," - " but format string expands to at least %2">, - InGroup<DiagGroup<"format-truncation">>; + " but format string expands to at least %2">; + +def warn_format_truncation: Warning< + "%sub{subst_format_truncation}0,1,2">, + InGroup<FormatTruncation>; + +def warn_format_truncation_non_kprintf: Warning< + "%sub{subst_format_truncation}0,1,2">, + InGroup<FormatTruncationNonKprintf>; def warn_fortify_scanf_overflow : Warning< "'%0' may overflow; destination buffer in argument %1 has size " diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 8260e72bd99e839..b29aa7f3996cd81 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -854,6 +854,9 @@ class ScanfDiagnosticFormatHandler class EstimateSizeFormatHandler : public analyze_format_string::FormatStringHandler { size_t Size; + /// Whether the format string contains Linux kernel's format specifier + /// extension. + bool IsKernelCompatible = true; public: EstimateSizeFormatHandler(StringRef Format) @@ -933,6 +936,10 @@ class EstimateSizeFormatHandler // Just a pointer in the form '0xddd'. case analyze_format_string::ConversionSpecifier::pArg: + // Linux kernel has its own extesion for `%p` specifier. + // Kernel Document: + // https://docs.kernel.org/core-api/printk-formats.html#pointer-types + IsKernelCompatible = false; Size += std::max(FieldWidth, 2 /* leading 0x */ + Precision); break; @@ -990,6 +997,7 @@ class EstimateSizeFormatHandler } size_t getSizeLowerBound() const { return Size; } + bool isKernelCompatible() const { return IsKernelCompatible; } private: static size_t computeFieldWidth(const analyze_printf::PrintfSpecifier &FS) { @@ -1259,7 +1267,9 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, if (!analyze_format_string::ParsePrintfString( H, FormatBytes, FormatBytes + StrLen, getLangOpts(), Context.getTargetInfo(), false)) { - DiagID = diag::warn_fortify_source_format_overflow; + DiagID = H.isKernelCompatible() + ? diag::warn_format_overflow + : diag::warn_format_overflow_non_kprintf; SourceSize = llvm::APSInt::getUnsigned(H.getSizeLowerBound()) .extOrTrunc(SizeTypeWidth); if (BuiltinID == Builtin::BI__builtin___sprintf_chk) { @@ -1350,12 +1360,15 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, llvm::APSInt::getUnsigned(H.getSizeLowerBound()) .extOrTrunc(SizeTypeWidth); if (FormatSize > *SourceSize && *SourceSize != 0) { + unsigned TruncationDiagID = + H.isKernelCompatible() ? diag::warn_format_truncation + : diag::warn_format_truncation_non_kprintf; SmallString<16> SpecifiedSizeStr; SmallString<16> FormatSizeStr; SourceSize->toString(SpecifiedSizeStr, /*Radix=*/10); FormatSize.toString(FormatSizeStr, /*Radix=*/10); DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall, - PDiag(diag::warn_fortify_source_format_truncation) + PDiag(TruncationDiagID) << GetFunctionName() << SpecifiedSizeStr << FormatSizeStr); } diff --git a/clang/test/Misc/warning-wall.c b/clang/test/Misc/warning-wall.c index a0bd571cab05139..57866713fc570f1 100644 --- a/clang/test/Misc/warning-wall.c +++ b/clang/test/Misc/warning-wall.c @@ -19,6 +19,10 @@ CHECK-NEXT: -Wformat-security CHECK-NEXT: -Wformat-y2k CHECK-NEXT: -Wformat-invalid-specifier CHECK-NEXT: -Wformat-insufficient-args +CHECK-NEXT: -Wformat-overflow +CHECK-NEXT: -Wformat-overflow-non-kprintf +CHECK-NEXT: -Wformat-truncation +CHECK-NEXT: -Wformat-truncation-non-kprintf CHECK-NEXT: -Wfor-loop-analysis CHECK-NEXT: -Wframe-address CHECK-NEXT: -Wimplicit diff --git a/clang/test/Sema/warn-format-overflow-truncation.c b/clang/test/Sema/warn-format-overflow-truncation.c index dada1f9355afe07..c64a1ed8aaa05a7 100644 --- a/clang/test/Sema/warn-format-overflow-truncation.c +++ b/clang/test/Sema/warn-format-overflow-truncation.c @@ -1,9 +1,11 @@ -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 %s -verify -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 %s -verify -DUSE_BUILTINS -// RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 %s -verify -// RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 %s -verify -DUSE_BUILTINS -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 -Wno-format-truncation -Wno-format-overflow %s -verify=off -// RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 -Wno-format-truncation -Wno-format-overflow %s -verify=off +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 %s -verify=kprintf,nonkprintf,expected +// RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 %s -verify=kprintf,nonkprintf,expected +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 -Wno-format-truncation -Wno-format-overflow %s -verify +// RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 -Wno-format-truncation -Wno-format-overflow %s -verify +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 -Wno-format-truncation-non-kprintf -Wno-format-overflow-non-kprintf %s -verify=kprintf,expected +// RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 -Wno-format-truncation-non-kprintf -Wno-format-overflow-non-kprintf %s -verify=kprintf,expected +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 -Wno-format-overflow -Wno-format-truncation -Wformat-truncation-non-kprintf -Wformat-overflow-non-kprintf %s -verify=nonkprintf,expected +// RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 -Wno-format-overflow -Wno-format-truncation -Wformat-truncation-non-kprintf -Wformat-overflow-non-kprintf %s -verify=nonkprintf,expected typedef unsigned long size_t; @@ -17,137 +19,138 @@ extern int sprintf(char *str, const char *format, ...); } #endif -void call_snprintf(double d, int n) { +void call_snprintf(double d, int n, int *ptr) { char buf[10]; __builtin_snprintf(buf, 10, "merp"); - __builtin_snprintf(buf, 11, "merp"); // expected-warning {{'snprintf' size argument is too large; destination buffer has size 10, but size argument is 11}} \ - // off-warning {{size argument is too large}} - __builtin_snprintf(buf, 12, "%#12x", n); // expected-warning {{'snprintf' will always be truncated; specified size is 12, but format string expands to at least 13}} \ - // expected-warning {{'snprintf' size argument is too large; destination buffer has size 10, but size argument is 12}} \ - // off-warning {{'snprintf' size argument is too large; destination buffer has size 10, but size argument is 12}} \ + __builtin_snprintf(buf, 11, "merp"); // expected-warning {{'snprintf' size argument is too large; destination buffer has size 10, but size argument is 11}} + __builtin_snprintf(buf, 12, "%#12x", n); // kprintf-warning {{'snprintf' will always be truncated; specified size is 12, but format string expands to at least 13}} \ + // expected-warning {{'snprintf' size argument is too large; destination buffer has size 10, but size argument is 12}} __builtin_snprintf(buf, 0, "merp"); - __builtin_snprintf(buf, 3, "merp"); // expected-warning {{'snprintf' will always be truncated; specified size is 3, but format string expands to at least 5}} - __builtin_snprintf(buf, 4, "merp"); // expected-warning {{'snprintf' will always be truncated; specified size is 4, but format string expands to at least 5}} + __builtin_snprintf(buf, 3, "merp"); // kprintf-warning {{'snprintf' will always be truncated; specified size is 3, but format string expands to at least 5}} + __builtin_snprintf(buf, 4, "merp"); // kprintf-warning {{'snprintf' will always be truncated; specified size is 4, but format string expands to at least 5}} __builtin_snprintf(buf, 5, "merp"); - __builtin_snprintf(buf, 1, "%.1000g", d); // expected-warning {{'snprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} + __builtin_snprintf(buf, 1, "%.1000g", d); // kprintf-warning {{'snprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} __builtin_snprintf(buf, 5, "%.1000g", d); __builtin_snprintf(buf, 5, "%.1000G", d); __builtin_snprintf(buf, 10, " %#08x", n); __builtin_snprintf(buf, 2, "%#x", n); __builtin_snprintf(buf, 2, "%#X", n); __builtin_snprintf(buf, 2, "%#o", n); - __builtin_snprintf(buf, 1, "%#x", n); // expected-warning {{'snprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} - __builtin_snprintf(buf, 1, "%#X", n); // expected-warning {{'snprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} - __builtin_snprintf(buf, 1, "%#o", n); // expected-warning {{'snprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} + __builtin_snprintf(buf, 1, "%#x", n); // kprintf-warning {{'snprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} + __builtin_snprintf(buf, 1, "%#X", n); // kprintf-warning {{'snprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} + __builtin_snprintf(buf, 1, "%#o", n); // kprintf-warning {{'snprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} + char node_name[6]; + __builtin_snprintf(node_name, sizeof(node_name), "%pOFn", ptr); // nonkprintf-warning {{'snprintf' will always be truncated; specified size is 6, but format string expands to at least 7}} + __builtin_snprintf(node_name, sizeof(node_name), "12345%pOFn", ptr); // nonkprintf-warning {{'snprintf' will always be truncated; specified size is 6, but format string expands to at least 12}} + __builtin_snprintf(node_name, sizeof(node_name), "123456%pOFn", ptr); // nonkprintf-warning {{'snprintf' will always be truncated; specified size is 6, but format string expands to at least 13}} } void call_vsnprintf(void) { char buf[10]; __builtin_va_list list; __builtin_vsnprintf(buf, 10, "merp", list); - __builtin_vsnprintf(buf, 11, "merp", list); // expected-warning {{'vsnprintf' size argument is too large; destination buffer has size 10, but size argument is 11}} \ - // off-warning {{size argument is too large}} + __builtin_vsnprintf(buf, 11, "merp", list); // expected-warning {{'vsnprintf' size argument is too large; destination buffer has size 10, but size argument is 11}} __builtin_vsnprintf(buf, 0, "merp", list); - __builtin_vsnprintf(buf, 3, "merp", list); // expected-warning {{'vsnprintf' will always be truncated; specified size is 3, but format string expands to at least 5}} - __builtin_vsnprintf(buf, 4, "merp", list); // expected-warning {{'vsnprintf' will always be truncated; specified size is 4, but format string expands to at least 5}} + __builtin_vsnprintf(buf, 3, "merp", list); // kprintf-warning {{'vsnprintf' will always be truncated; specified size is 3, but format string expands to at least 5}} + __builtin_vsnprintf(buf, 4, "merp", list); // kprintf-warning {{'vsnprintf' will always be truncated; specified size is 4, but format string expands to at least 5}} __builtin_vsnprintf(buf, 5, "merp", list); - __builtin_vsnprintf(buf, 1, "%.1000g", list); // expected-warning {{'vsnprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} + __builtin_vsnprintf(buf, 1, "%.1000g", list); // kprintf-warning {{'vsnprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} __builtin_vsnprintf(buf, 5, "%.1000g", list); __builtin_vsnprintf(buf, 5, "%.1000G", list); __builtin_vsnprintf(buf, 10, " %#08x", list); __builtin_vsnprintf(buf, 2, "%#x", list); __builtin_vsnprintf(buf, 2, "%#X", list); __builtin_vsnprintf(buf, 2, "%#o", list); - __builtin_vsnprintf(buf, 1, "%#x", list); // expected-warning {{'vsnprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} - __builtin_vsnprintf(buf, 1, "%#X", list); // expected-warning {{'vsnprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} - __builtin_vsnprintf(buf, 1, "%#o", list); // expected-warning {{'vsnprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} + __builtin_vsnprintf(buf, 1, "%#x", list); // kprintf-warning {{'vsnprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} + __builtin_vsnprintf(buf, 1, "%#X", list); // kprintf-warning {{'vsnprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} + __builtin_vsnprintf(buf, 1, "%#o", list); // kprintf-warning {{'vsnprintf' will always be truncated; specified size is 1, but format string expands to at least 2}} + char node_name[6]; + __builtin_snprintf(node_name, sizeof(node_name), "%pOFn", list); // nonkprintf-warning {{'snprintf' will always be truncated; specified size is 6, but format string expands to at least 7}} + __builtin_snprintf(node_name, sizeof(node_name), "12345%pOFn", list); // nonkprintf-warning {{'snprintf' will always be truncated; specified size is 6, but format string expands to at least 12}} + __builtin_snprintf(node_name, sizeof(node_name), "123456%pOFn", list); // nonkprintf-warning {{'snprintf' will always be truncated; specified size is 6, but format string expands to at least 13}} } void call_sprintf_chk(char *buf) { __builtin___sprintf_chk(buf, 1, 6, "hell\n"); - __builtin___sprintf_chk(buf, 1, 5, "hell\n"); // expected-warning {{'sprintf' will always overflow; destination buffer has size 5, but format string expands to at least 6}} - __builtin___sprintf_chk(buf, 1, 6, "hell\0 boy"); // expected-warning {{format string contains '\0' within the string body}} \ - // off-warning {{format string contains '\0' within the string body}} + __builtin___sprintf_chk(buf, 1, 5, "hell\n"); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 5, but format string expands to at least 6}} + __builtin___sprintf_chk(buf, 1, 6, "hell\0 boy"); // expected-warning {{format string contains '\0' within the string body}} __builtin___sprintf_chk(buf, 1, 2, "hell\0 boy"); // expected-warning {{format string contains '\0' within the string body}} \ - // off-warning {{format string contains '\0' within the string body}} \ - // expected-warning {{'sprintf' will always overflow; destination buffer has size 2, but format string expands to at least 5}} + // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 2, but format string expands to at least 5}} __builtin___sprintf_chk(buf, 1, 6, "hello"); - __builtin___sprintf_chk(buf, 1, 5, "hello"); // expected-warning {{'sprintf' will always overflow; destination buffer has size 5, but format string expands to at least 6}} + __builtin___sprintf_chk(buf, 1, 5, "hello"); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 5, but format string expands to at least 6}} __builtin___sprintf_chk(buf, 1, 2, "%c", '9'); - __builtin___sprintf_chk(buf, 1, 1, "%c", '9'); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 1, "%c", '9'); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} __builtin___sprintf_chk(buf, 1, 2, "%d", 9); - __builtin___sprintf_chk(buf, 1, 1, "%d", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 1, "%d", 9); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} __builtin___sprintf_chk(buf, 1, 2, "%i", 9); - __builtin___sprintf_chk(buf, 1, 1, "%i", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 1, "%i", 9); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} __builtin___sprintf_chk(buf, 1, 2, "%o", 9); - __builtin___sprintf_chk(buf, 1, 1, "%o", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 1, "%o", 9); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} __builtin___sprintf_chk(buf, 1, 2, "%u", 9); - __builtin___sprintf_chk(buf, 1, 1, "%u", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 1, "%u", 9); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} __builtin___sprintf_chk(buf, 1, 2, "%x", 9); - __builtin___sprintf_chk(buf, 1, 1, "%x", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 1, "%x", 9); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} __builtin___sprintf_chk(buf, 1, 2, "%X", 9); - __builtin___sprintf_chk(buf, 1, 1, "%X", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 1, "%X", 9); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} __builtin___sprintf_chk(buf, 1, 2, "%hhd", (char)9); - __builtin___sprintf_chk(buf, 1, 1, "%hhd", (char)9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 1, "%hhd", (char)9); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} __builtin___sprintf_chk(buf, 1, 2, "%hd", (short)9); - __builtin___sprintf_chk(buf, 1, 1, "%hd", (short)9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 1, "%hd", (short)9); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} __builtin___sprintf_chk(buf, 1, 2, "%ld", 9l); - __builtin___sprintf_chk(buf, 1, 1, "%ld", 9l); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 1, "%ld", 9l); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} __builtin___sprintf_chk(buf, 1, 2, "%lld", 9ll); - __builtin___sprintf_chk(buf, 1, 1, "%lld", 9ll); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 1, "%lld", 9ll); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} __builtin___sprintf_chk(buf, 1, 2, "%%"); - __builtin___sprintf_chk(buf, 1, 1, "%%"); // expected-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} + __builtin___sprintf_chk(buf, 1, 1, "%%"); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 1, but format string expands to at least 2}} __builtin___sprintf_chk(buf, 1, 4, "%#x", 9); __builtin___sprintf_chk(buf, 1, 3, "%#x", 9); __builtin___sprintf_chk(buf, 1, 4, "%p", (void *)9); - __builtin___sprintf_chk(buf, 1, 3, "%p", (void *)9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 3, but format string expands to at least 4}} + __builtin___sprintf_chk(buf, 1, 3, "%p", (void *)9); // nonkprintf-warning {{'sprintf' will always overflow; destination buffer has size 3, but format string expands to at least 4}} __builtin___sprintf_chk(buf, 1, 3, "%+d", 9); - __builtin___sprintf_chk(buf, 1, 2, "%+d", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 2, but format string expands to at least 3}} + __builtin___sprintf_chk(buf, 1, 2, "%+d", 9); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 2, but format string expands to at least 3}} __builtin___sprintf_chk(buf, 1, 3, "% i", 9); - __builtin___sprintf_chk(buf, 1, 2, "% i", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 2, but format string expands to at least 3}} + __builtin___sprintf_chk(buf, 1, 2, "% i", 9); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 2, but format string expands to at least 3}} __builtin___sprintf_chk(buf, 1, 6, "%5d", 9); - __builtin___sprintf_chk(buf, 1, 5, "%5d", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 5, but format string expands to at least 6}} + __builtin___sprintf_chk(buf, 1, 5, "%5d", 9); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 5, but format string expands to at least 6}} __builtin___sprintf_chk(buf, 1, 9, "%f", 9.f); - __builtin___sprintf_chk(buf, 1, 8, "%f", 9.f); // expected-warning {{'sprintf' will always overflow; destination buffer has size 8, but format string expands to at least 9}} + __builtin___sprintf_chk(buf, 1, 8, "%f", 9.f); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 8, but format string expands to at least 9}} __builtin___sprintf_chk(buf, 1, 9, "%Lf", (long double)9.); - __builtin___sprintf_chk(buf, 1, 8, "%Lf", (long double)9.); // expected-warning {{'sprintf' will always overflow; destination buffer has size 8, but format string expands to at least 9}} + __builtin___sprintf_chk(buf, 1, 8, "%Lf", (long double)9.); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 8, but format string expands to at least 9}} __builtin___sprintf_chk(buf, 1, 10, "%+f", 9.f); - __builtin___sprintf_chk(buf, 1, 9, "%+f", 9.f); // expected-warning {{'sprintf' will always overflow; destination buffer has size 9, but format string expands to at least 10}} + __builtin___sprintf_chk(buf, 1, 9, "%+f", 9.f); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 9, but format string expands to at least 10}} __builtin___sprintf_chk(buf, 1, 12, "%e", 9.f); - __builtin___sprintf_chk(buf, 1, 11, "%e", 9.f); // expected-warning {{'sprintf' will always overflow; destination buffer has size 11, but format string expands to at least 12}} + __builtin___sprintf_chk(buf, 1, 11, "%e", 9.f); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 11, but format string expands to at least 12}} } void call_sprintf(void) { char buf[6]; - sprintf(buf, "hell\0 boy"); // expected-warning {{format string contains '\0' within the string body}} \ - // off-warning {{format string contains '\0' within the string body}} + sprintf(buf, "hell\0 boy"); // expected-warning {{format string contains '\0' within the string body}} sprintf(buf, "hello b\0y"); // expected-warning {{format string contains '\0' within the string body}} \ - // off-warning {{format string contains '\0' within the string body}} \ - // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 8}} + // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 8}} sprintf(buf, "hello"); - sprintf(buf, "hello!"); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "hello!"); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} sprintf(buf, "1234%%"); - sprintf(buf, "12345%%"); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "12345%%"); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} sprintf(buf, "1234%c", '9'); - sprintf(buf, "12345%c", '9'); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "12345%c", '9'); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} sprintf(buf, "1234%d", 9); - sprintf(buf, "12345%d", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "12345%d", 9); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} sprintf(buf, "1234%lld", 9ll); - sprintf(buf, "12345%lld", 9ll); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "12345%lld", 9ll); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} sprintf(buf, "12%#x", 9); sprintf(buf, "123%#x", 9); sprintf(buf, "12%p", (void *)9); - sprintf(buf, "123%p", (void *)9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "123%p", (void *)9); // nonkprintf-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} sprintf(buf, "123%+d", 9); - sprintf(buf, "1234%+d", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "1234%+d", 9); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} sprintf(buf, "123% i", 9); - sprintf(buf, "1234% i", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "1234% i", 9); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} sprintf(buf, "%5d", 9); - sprintf(buf, "1%5d", 9); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "1%5d", 9); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} sprintf(buf, "%.3f", 9.f); - sprintf(buf, "5%.3f", 9.f); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "5%.3f", 9.f); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} sprintf(buf, "%+.2f", 9.f); - sprintf(buf, "%+.3f", 9.f); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} + sprintf(buf, "%+.3f", 9.f); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 7}} sprintf(buf, "%.0e", 9.f); - sprintf(buf, "5%.1e", 9.f); // expected-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 8}} + sprintf(buf, "5%.1e", 9.f); // kprintf-warning {{'sprintf' will always overflow; destination buffer has size 6, but format string expands to at least 8}} } >From e9513030fb9dddc82aeab8ae58a7af7b5c56015d Mon Sep 17 00:00:00 2001 From: Takuya Shimizu <shimizu2...@gmail.com> Date: Thu, 14 Sep 2023 23:09:22 +0900 Subject: [PATCH 3/4] Make `-Wformat-overflow` and `-Wformat-truncation` grouped in `-Wfortify-source` as well as `-Wformat` --- clang/include/clang/Basic/DiagnosticGroups.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 162eff37cc910c0..afbf0f0ed22e57f 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1406,7 +1406,7 @@ def CrossTU : DiagGroup<"ctu">; def CTADMaybeUnsupported : DiagGroup<"ctad-maybe-unsupported">; -def FortifySource : DiagGroup<"fortify-source">; +def FortifySource : DiagGroup<"fortify-source", [FormatOverflow, FormatTruncation]>; def MaxTokens : DiagGroup<"max-tokens"> { code Documentation = [{ >From 34777e61172061b651965a294190b9e7ab5f8189 Mon Sep 17 00:00:00 2001 From: Takuya Shimizu <shimizu2...@gmail.com> Date: Mon, 18 Sep 2023 17:40:56 +0900 Subject: [PATCH 4/4] [NFC] fix typo in release note --- clang/docs/ReleaseNotes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5c2779009ec6a18..c46d6a662cefd9c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -171,7 +171,7 @@ Improvements to Clang's diagnostics the format string contains ``%p`` format specifier. Because Linux kernel's codebase has format extensions for ``%p``, kernel developers are encouraged to disable these two subgroups by setting ``-Wno-format-truncation-non-kprintf`` - and ``-Wno-format-truncation-non-kprintf`` in order to avoid false positives on + and ``-Wno-format-overflow-non-kprintf`` in order to avoid false positives on the kernel codebase. Also clang no longer emits false positive warnings about the output length of ``%g`` format specifier and about ``%o, %x, %X`` with ``#`` flag. _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits