https://github.com/ZijunZhaoCCK updated https://github.com/llvm/llvm-project/pull/71771
>From 06c4cf02dfb4b20c8349c5f3c7209276f6d56edf Mon Sep 17 00:00:00 2001 From: zijunzhao <zijunz...@google.com> Date: Thu, 9 Nov 2023 02:21:46 +0000 Subject: [PATCH 1/4] Fix clang to recognize new C23 modifiers %w and %wf when printing --- clang/include/clang/AST/FormatString.h | 16 +++++++- clang/lib/AST/FormatString.cpp | 52 +++++++++++++++++++++++++- clang/lib/AST/PrintfFormatString.cpp | 19 ++++++++++ clang/test/Sema/format-strings-ms.c | 28 ++++++++++++++ 4 files changed, 112 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/AST/FormatString.h b/clang/include/clang/AST/FormatString.h index 5c4ad9baaef608c..6a886854650f1d9 100644 --- a/clang/include/clang/AST/FormatString.h +++ b/clang/include/clang/AST/FormatString.h @@ -81,8 +81,10 @@ class LengthModifier { AsLongDouble, // 'L' AsAllocate, // for '%as', GNU extension to C90 scanf AsMAllocate, // for '%ms', GNU extension to scanf - AsWide, // 'w' (MSVCRT, like l but only for c, C, s, S, or Z - AsWideChar = AsLong // for '%ls', only makes sense for printf + AsWide, // 'w' (1. MSVCRT, like l but only for c, C, s, S, or Z on windows + // 2. for b, d, i, o, u, x, or X when a size followed(like 8, 16, 32 or 64) + AsWideFast, // 'wf' (for b, d, i, o, u, x, or X) + AsWideChar = AsLong, // for '%ls', only makes sense for printf }; LengthModifier() @@ -417,6 +419,7 @@ class FormatSpecifier { /// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html bool UsesPositionalArg; unsigned argIndex; + unsigned size; public: FormatSpecifier(bool isPrintf) : CS(isPrintf), VectorNumElts(false), @@ -460,6 +463,15 @@ class FormatSpecifier { FieldWidth = Amt; } + void setSize(unsigned s) { + size = s; + } + + unsigned getSize() const { + return size; + } + + bool usesPositionalArg() const { return UsesPositionalArg; } bool hasValidLengthModifier(const TargetInfo &Target, diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp index e0c9e18cfe3a243..ebc136e780717e4 100644 --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -286,7 +286,33 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS, lmKind = LengthModifier::AsInt3264; break; case 'w': - lmKind = LengthModifier::AsWide; ++I; break; + ++I; + if (I == E) return false; + if (*I == 'f') { + lmKind = LengthModifier::AsWideFast; + ++I; + } else { + lmKind = LengthModifier::AsWide; + } + + if (I == E) return false; + int s = 0; + while (unsigned(*I - '0') <= 9) { + s = 10 * s + unsigned(*I - '0'); + ++I; + } + + // s == 0 is MSVCRT case, like l but only for c, C, s, S, or Z on windows + // s != 0 for b, d, i, o, u, x, or X when a size followed(like 8, 16, 32 or 64) + if (s != 0) { + std::set<int> supported_list {8, 16, 32, 64}; + if (supported_list.count(s) == 0) { + return false; + } + FS.setSize(s); + } + + break; } LengthModifier lm(lmPosition, lmKind); FS.setLengthModifier(lm); @@ -703,6 +729,8 @@ analyze_format_string::LengthModifier::toString() const { return "m"; case AsWide: return "w"; + case AsWideFast: + return "wf"; case None: return ""; } @@ -970,6 +998,27 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target, case ConversionSpecifier::SArg: case ConversionSpecifier::ZArg: return Target.getTriple().isOSMSVCRT(); + case ConversionSpecifier::bArg: + case ConversionSpecifier::dArg: + case ConversionSpecifier::iArg: + case ConversionSpecifier::oArg: + case ConversionSpecifier::uArg: + case ConversionSpecifier::xArg: + case ConversionSpecifier::XArg: + return true; + default: + return false; + } + case LengthModifier::AsWideFast: + switch (CS.getKind()) { + case ConversionSpecifier::bArg: + case ConversionSpecifier::dArg: + case ConversionSpecifier::iArg: + case ConversionSpecifier::oArg: + case ConversionSpecifier::uArg: + case ConversionSpecifier::xArg: + case ConversionSpecifier::XArg: + return true; default: return false; } @@ -996,6 +1045,7 @@ bool FormatSpecifier::hasStandardLengthModifier() const { case LengthModifier::AsInt3264: case LengthModifier::AsInt64: case LengthModifier::AsWide: + case LengthModifier::AsWideFast: case LengthModifier::AsShortLong: // ??? return false; } diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp index f0b9d0ecaf23461..4b9111e8bcf509a 100644 --- a/clang/lib/AST/PrintfFormatString.cpp +++ b/clang/lib/AST/PrintfFormatString.cpp @@ -537,7 +537,16 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); case LengthModifier::AsAllocate: case LengthModifier::AsMAllocate: + return ArgType::Invalid(); case LengthModifier::AsWide: + case LengthModifier::AsWideFast: + int s = getSize(); + bool fast = LM.getKind() == LengthModifier::AsWideFast ? true : false; + ArgType fastType = Ctx.getTargetInfo().getTriple().isArch64Bit() ? Ctx.LongLongTy : Ctx.IntTy; + if (s == 8) return Ctx.CharTy; + if (s == 16) return fast? fastType : Ctx.ShortTy; + if (s == 32) return fast? fastType : Ctx.IntTy; + if (s == 64) return Ctx.LongLongTy; return ArgType::Invalid(); } @@ -572,7 +581,16 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t")); case LengthModifier::AsAllocate: case LengthModifier::AsMAllocate: + return ArgType::Invalid(); case LengthModifier::AsWide: + case LengthModifier::AsWideFast: + int s = getSize(); + bool fast = LM.getKind() == LengthModifier::AsWideFast ? true : false; + ArgType fastType = Ctx.getTargetInfo().getTriple().isArch64Bit() ? Ctx.UnsignedLongLongTy : Ctx.UnsignedIntTy; + if (s == 8) return Ctx.UnsignedCharTy; + if (s == 16) return fast? fastType : Ctx.UnsignedShortTy; + if (s == 32) return fast? fastType : Ctx.UnsignedIntTy; + if (s == 64) return Ctx.UnsignedLongLongTy; return ArgType::Invalid(); } @@ -621,6 +639,7 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, case LengthModifier::AsInt3264: case LengthModifier::AsInt64: case LengthModifier::AsWide: + case LengthModifier::AsWideFast: return ArgType::Invalid(); case LengthModifier::AsShortLong: llvm_unreachable("only used for OpenCL which doesn not handle nArg"); diff --git a/clang/test/Sema/format-strings-ms.c b/clang/test/Sema/format-strings-ms.c index 697032673d4e770..59ae930bb734eb6 100644 --- a/clang/test/Sema/format-strings-ms.c +++ b/clang/test/Sema/format-strings-ms.c @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify -fms-compatibility -triple=i386-pc-win32 %s // RUN: %clang_cc1 -fsyntax-only -verify -fms-compatibility -triple=i386-pc-win32 -Wformat-non-iso -DNON_ISO_WARNING %s +#include <stdint.h> int printf(const char *format, ...) __attribute__((format(printf, 1, 2))); int scanf(const char * restrict, ...) ; typedef unsigned short wchar_t; @@ -85,4 +86,31 @@ void z_test(void *p) { scanf("%Z", p); // expected-warning{{invalid conversion specifier 'Z'}} } +void w_int_test(void) { + int8_t a = 0b101; + int16_t b = 2; + uint32_t c = 123; + int64_t d = 0x3b; + + // for %w + printf("%w8b", a); // expected-warning{{format specifies type 'char' but the argument has type 'int8_t' (aka 'signed char')}} + printf("%w16i", b); + printf("%w32u", c); + printf("%w64x", d); + +} + +void wf_test(void) { + int_fast8_t a = 0b101; + uint_fast16_t b = 2; + int_fast32_t c = 021; + int_fast64_t d = 0x3a; + + // for %wf + printf("%wf8b", a); // expected-warning{{format specifies type 'char' but the argument has type 'int_fast8_t' (aka 'signed char')}} + printf("%wf16u", b); + printf("%wf32o", c); + printf("%wf64X", d); +} + #endif >From 2ec84a88a9ba6e4576a855b419dd6bafa9f3d721 Mon Sep 17 00:00:00 2001 From: zijunzhao <zijunz...@google.com> Date: Tue, 14 Nov 2023 00:38:41 +0000 Subject: [PATCH 2/4] Update code and tests. %w and %wf are available in printf() and scanf() --- clang/include/clang/AST/FormatString.h | 4 ++- clang/lib/AST/PrintfFormatString.cpp | 34 +++++++++++++++++--------- clang/lib/AST/ScanfFormatString.cpp | 14 +++++++++-- clang/test/Sema/format-strings-ms.c | 25 ++++++++++++------- 4 files changed, 53 insertions(+), 24 deletions(-) diff --git a/clang/include/clang/AST/FormatString.h b/clang/include/clang/AST/FormatString.h index 6a886854650f1d9..2e48a8ddfde4d39 100644 --- a/clang/include/clang/AST/FormatString.h +++ b/clang/include/clang/AST/FormatString.h @@ -471,7 +471,6 @@ class FormatSpecifier { return size; } - bool usesPositionalArg() const { return UsesPositionalArg; } bool hasValidLengthModifier(const TargetInfo &Target, @@ -792,6 +791,9 @@ bool parseFormatStringHasFormattingSpecifiers(const char *Begin, const LangOptions &LO, const TargetInfo &Target); +ArgType wToArgType(int size, bool fast, ASTContext &C); +ArgType wToArgTypeUnsigned(int size, bool fast, ASTContext &C); + } // end analyze_format_string namespace } // end clang namespace #endif diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp index 4b9111e8bcf509a..e6e47403198af77 100644 --- a/clang/lib/AST/PrintfFormatString.cpp +++ b/clang/lib/AST/PrintfFormatString.cpp @@ -484,6 +484,26 @@ bool clang::analyze_format_string::parseFormatStringHasFormattingSpecifiers( return false; } +ArgType clang::analyze_format_string::wToArgType( + int size, bool fast, ASTContext &C) { + ArgType fastType = C.getTargetInfo().getTriple().isArch64Bit() ? C.LongLongTy : C.IntTy; + if (size == 8) return C.CharTy; + if (size == 16) return fast? fastType : C.ShortTy; + if (size == 32) return fast? fastType : C.IntTy; + if (size == 64) return C.LongLongTy; + return ArgType::Invalid(); +} + +ArgType clang::analyze_format_string::wToArgTypeUnsigned( + int size, bool fast, ASTContext &C) { + ArgType fastType = C.getTargetInfo().getTriple().isArch64Bit() ? C.UnsignedLongLongTy : C.UnsignedIntTy; + if (size == 8) return C.UnsignedCharTy; + if (size == 16) return fast? fastType : C.UnsignedShortTy; + if (size == 32) return fast? fastType : C.UnsignedIntTy; + if (size == 64) return C.UnsignedLongLongTy; + return ArgType::Invalid(); +} + //===----------------------------------------------------------------------===// // Methods on PrintfSpecifier. //===----------------------------------------------------------------------===// @@ -542,12 +562,7 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, case LengthModifier::AsWideFast: int s = getSize(); bool fast = LM.getKind() == LengthModifier::AsWideFast ? true : false; - ArgType fastType = Ctx.getTargetInfo().getTriple().isArch64Bit() ? Ctx.LongLongTy : Ctx.IntTy; - if (s == 8) return Ctx.CharTy; - if (s == 16) return fast? fastType : Ctx.ShortTy; - if (s == 32) return fast? fastType : Ctx.IntTy; - if (s == 64) return Ctx.LongLongTy; - return ArgType::Invalid(); + return clang::analyze_format_string::wToArgType(s, fast, Ctx); } if (CS.isUIntArg()) @@ -586,12 +601,7 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, case LengthModifier::AsWideFast: int s = getSize(); bool fast = LM.getKind() == LengthModifier::AsWideFast ? true : false; - ArgType fastType = Ctx.getTargetInfo().getTriple().isArch64Bit() ? Ctx.UnsignedLongLongTy : Ctx.UnsignedIntTy; - if (s == 8) return Ctx.UnsignedCharTy; - if (s == 16) return fast? fastType : Ctx.UnsignedShortTy; - if (s == 32) return fast? fastType : Ctx.UnsignedIntTy; - if (s == 64) return Ctx.UnsignedLongLongTy; - return ArgType::Invalid(); + return clang::analyze_format_string::wToArgTypeUnsigned(s, fast, Ctx); } if (CS.isDoubleArg()) { diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp index 64c430e623b577e..e640bc2de4d259c 100644 --- a/clang/lib/AST/ScanfFormatString.cpp +++ b/clang/lib/AST/ScanfFormatString.cpp @@ -261,9 +261,13 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::AsMAllocate: case LengthModifier::AsInt32: case LengthModifier::AsInt3264: - case LengthModifier::AsWide: case LengthModifier::AsShortLong: return ArgType::Invalid(); + case LengthModifier::AsWide: + case LengthModifier::AsWideFast: + int s = getSize(); + bool fast = LM.getKind() == LengthModifier::AsWideFast ? true : false; + return clang::analyze_format_string::wToArgType(s, fast, Ctx); } llvm_unreachable("Unsupported LengthModifier Type"); @@ -303,9 +307,15 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::AsMAllocate: case LengthModifier::AsInt32: case LengthModifier::AsInt3264: - case LengthModifier::AsWide: case LengthModifier::AsShortLong: return ArgType::Invalid(); + case LengthModifier::AsWide: + case LengthModifier::AsWideFast: + int s = getSize(); + bool fast = LM.getKind() == LengthModifier::AsWideFast ? true : false; + if (CS.getKind() == ConversionSpecifier::uArg or CS.getKind() == ConversionSpecifier::UArg) + return clang::analyze_format_string::wToArgTypeUnsigned(s, fast, Ctx); + return clang::analyze_format_string::wToArgType(s, fast, Ctx); } llvm_unreachable("Unsupported LengthModifier Type"); diff --git a/clang/test/Sema/format-strings-ms.c b/clang/test/Sema/format-strings-ms.c index 59ae930bb734eb6..bca824533d128ae 100644 --- a/clang/test/Sema/format-strings-ms.c +++ b/clang/test/Sema/format-strings-ms.c @@ -87,30 +87,37 @@ void z_test(void *p) { } void w_int_test(void) { - int8_t a = 0b101; - int16_t b = 2; - uint32_t c = 123; - int64_t d = 0x3b; + int8_t a; + int16_t b; + uint32_t c; + int64_t d; // for %w printf("%w8b", a); // expected-warning{{format specifies type 'char' but the argument has type 'int8_t' (aka 'signed char')}} printf("%w16i", b); printf("%w32u", c); printf("%w64x", d); - + scanf("%w8b", a); // expected-warning{{format specifies type 'char' but the argument has type 'int'}} + scanf("%w16i", b); // expected-warning{{format specifies type 'short' but the argument has type 'int'}} + scanf("%w32u", c); + scanf("%w64x", d); } void wf_test(void) { - int_fast8_t a = 0b101; - uint_fast16_t b = 2; - int_fast32_t c = 021; - int_fast64_t d = 0x3a; + int_fast8_t a; + uint_fast16_t b; + int_fast32_t c; + int_fast64_t d; // for %wf printf("%wf8b", a); // expected-warning{{format specifies type 'char' but the argument has type 'int_fast8_t' (aka 'signed char')}} printf("%wf16u", b); printf("%wf32o", c); printf("%wf64X", d); + scanf("%wf8b", a); // expected-warning{{format specifies type 'char' but the argument has type 'int'}} + scanf("%wf16u", b); + scanf("%wf32o", c); + scanf("%wf64X", d); } #endif >From 1431133f1e48bb58fa407e4a6d985fca24e9410b Mon Sep 17 00:00:00 2001 From: zijunzhao <zijunz...@google.com> Date: Tue, 14 Nov 2023 00:38:41 +0000 Subject: [PATCH 3/4] Update code and tests. %w and %wf are available in printf() and scanf() --- clang/include/clang/AST/FormatString.h | 14 ++++++------- clang/lib/AST/FormatString.cpp | 2 +- clang/lib/AST/PrintfFormatString.cpp | 28 +++++++++++++------------- clang/lib/AST/ScanfFormatString.cpp | 4 ++-- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/clang/include/clang/AST/FormatString.h b/clang/include/clang/AST/FormatString.h index 2e48a8ddfde4d39..dba973ffcaa4ef9 100644 --- a/clang/include/clang/AST/FormatString.h +++ b/clang/include/clang/AST/FormatString.h @@ -419,7 +419,7 @@ class FormatSpecifier { /// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html bool UsesPositionalArg; unsigned argIndex; - unsigned size; + unsigned ExplicitlyFixedSize; public: FormatSpecifier(bool isPrintf) : CS(isPrintf), VectorNumElts(false), @@ -463,12 +463,12 @@ class FormatSpecifier { FieldWidth = Amt; } - void setSize(unsigned s) { - size = s; + void setExplicitlyFixedSize(unsigned s) { + ExplicitlyFixedSize = s; } - unsigned getSize() const { - return size; + unsigned getExplicitlyFixedSize() const { + return ExplicitlyFixedSize; } bool usesPositionalArg() const { return UsesPositionalArg; } @@ -791,8 +791,8 @@ bool parseFormatStringHasFormattingSpecifiers(const char *Begin, const LangOptions &LO, const TargetInfo &Target); -ArgType wToArgType(int size, bool fast, ASTContext &C); -ArgType wToArgTypeUnsigned(int size, bool fast, ASTContext &C); +ArgType wToArgType(int Size, bool Fast, ASTContext &C); +ArgType wToArgTypeUnsigned(int Size, bool Fast, ASTContext &C); } // end analyze_format_string namespace } // end clang namespace diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp index ebc136e780717e4..88d0f1c98ed0d2f 100644 --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -309,7 +309,7 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS, if (supported_list.count(s) == 0) { return false; } - FS.setSize(s); + FS.setExplicitlyFixedSize(s); } break; diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp index e6e47403198af77..ad92fb3aab97d86 100644 --- a/clang/lib/AST/PrintfFormatString.cpp +++ b/clang/lib/AST/PrintfFormatString.cpp @@ -485,22 +485,22 @@ bool clang::analyze_format_string::parseFormatStringHasFormattingSpecifiers( } ArgType clang::analyze_format_string::wToArgType( - int size, bool fast, ASTContext &C) { - ArgType fastType = C.getTargetInfo().getTriple().isArch64Bit() ? C.LongLongTy : C.IntTy; - if (size == 8) return C.CharTy; - if (size == 16) return fast? fastType : C.ShortTy; - if (size == 32) return fast? fastType : C.IntTy; - if (size == 64) return C.LongLongTy; + int Size, bool Fast, ASTContext &C) { + ArgType FastType = C.getTargetInfo().getTriple().isArch64Bit() ? C.LongLongTy : C.IntTy; + if (Size == 8) return C.CharTy; + if (Size == 16) return Fast? FastType : C.ShortTy; + if (Size == 32) return Fast? FastType : C.IntTy; + if (Size == 64) return C.LongLongTy; return ArgType::Invalid(); } ArgType clang::analyze_format_string::wToArgTypeUnsigned( - int size, bool fast, ASTContext &C) { - ArgType fastType = C.getTargetInfo().getTriple().isArch64Bit() ? C.UnsignedLongLongTy : C.UnsignedIntTy; - if (size == 8) return C.UnsignedCharTy; - if (size == 16) return fast? fastType : C.UnsignedShortTy; - if (size == 32) return fast? fastType : C.UnsignedIntTy; - if (size == 64) return C.UnsignedLongLongTy; + int Size, bool Fast, ASTContext &C) { + ArgType FastType = C.getTargetInfo().getTriple().isArch64Bit() ? C.UnsignedLongLongTy : C.UnsignedIntTy; + if (Size == 8) return C.UnsignedCharTy; + if (Size == 16) return Fast? FastType : C.UnsignedShortTy; + if (Size == 32) return Fast? FastType : C.UnsignedIntTy; + if (Size == 64) return C.UnsignedLongLongTy; return ArgType::Invalid(); } @@ -560,7 +560,7 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, return ArgType::Invalid(); case LengthModifier::AsWide: case LengthModifier::AsWideFast: - int s = getSize(); + int s = getExplicitlyFixedSize(); bool fast = LM.getKind() == LengthModifier::AsWideFast ? true : false; return clang::analyze_format_string::wToArgType(s, fast, Ctx); } @@ -599,7 +599,7 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, return ArgType::Invalid(); case LengthModifier::AsWide: case LengthModifier::AsWideFast: - int s = getSize(); + int s = getExplicitlyFixedSize(); bool fast = LM.getKind() == LengthModifier::AsWideFast ? true : false; return clang::analyze_format_string::wToArgTypeUnsigned(s, fast, Ctx); } diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp index e640bc2de4d259c..6f856f1b0bedbd4 100644 --- a/clang/lib/AST/ScanfFormatString.cpp +++ b/clang/lib/AST/ScanfFormatString.cpp @@ -265,7 +265,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { return ArgType::Invalid(); case LengthModifier::AsWide: case LengthModifier::AsWideFast: - int s = getSize(); + int s = getExplicitlyFixedSize(); bool fast = LM.getKind() == LengthModifier::AsWideFast ? true : false; return clang::analyze_format_string::wToArgType(s, fast, Ctx); } @@ -311,7 +311,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { return ArgType::Invalid(); case LengthModifier::AsWide: case LengthModifier::AsWideFast: - int s = getSize(); + int s = getExplicitlyFixedSize(); bool fast = LM.getKind() == LengthModifier::AsWideFast ? true : false; if (CS.getKind() == ConversionSpecifier::uArg or CS.getKind() == ConversionSpecifier::UArg) return clang::analyze_format_string::wToArgTypeUnsigned(s, fast, Ctx); >From b4ff31c11d64079456cda63bed1a734958754b10 Mon Sep 17 00:00:00 2001 From: zijunzhao <zijunz...@google.com> Date: Sat, 2 Dec 2023 01:35:09 +0000 Subject: [PATCH 4/4] 1. add one more warning about unsupported sizes 2. reformat --- clang/include/clang/AST/FormatString.h | 16 +++++++++++--- .../clang/Basic/DiagnosticSemaKinds.td | 4 ++++ clang/lib/AST/FormatString.cpp | 13 ++++++----- clang/lib/AST/PrintfFormatString.cpp | 6 ++--- clang/lib/AST/ScanfFormatString.cpp | 6 ++--- clang/lib/Sema/SemaChecking.cpp | 22 +++++++++++++++++++ clang/test/Sema/format-strings-ms.c | 8 +++++++ 7 files changed, 60 insertions(+), 15 deletions(-) diff --git a/clang/include/clang/AST/FormatString.h b/clang/include/clang/AST/FormatString.h index dba973ffcaa4ef9..c3f761ed03d9f44 100644 --- a/clang/include/clang/AST/FormatString.h +++ b/clang/include/clang/AST/FormatString.h @@ -420,10 +420,12 @@ class FormatSpecifier { bool UsesPositionalArg; unsigned argIndex; unsigned ExplicitlyFixedSize; + bool ExplicitlyFixedSizeValid; + public: FormatSpecifier(bool isPrintf) : CS(isPrintf), VectorNumElts(false), - UsesPositionalArg(false), argIndex(0) {} + UsesPositionalArg(false), argIndex(0), ExplicitlyFixedSizeValid(true) {} void setLengthModifier(LengthModifier lm) { LM = lm; @@ -463,8 +465,8 @@ class FormatSpecifier { FieldWidth = Amt; } - void setExplicitlyFixedSize(unsigned s) { - ExplicitlyFixedSize = s; + void setExplicitlyFixedSize(unsigned S) { + ExplicitlyFixedSize = S; } unsigned getExplicitlyFixedSize() const { @@ -478,6 +480,14 @@ class FormatSpecifier { bool hasStandardLengthModifier() const; + void setExplicitlyFixedSizeValid(bool valid) { + ExplicitlyFixedSizeValid = valid; + } + + bool isExplicitlyFixedSizeSupported() const { + return ExplicitlyFixedSizeValid; + } + std::optional<LengthModifier> getCorrectedLengthModifier() const; bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6dfb2d7195203a3..5d1dcb66d29903f 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9707,6 +9707,10 @@ def warn_missing_format_string : Warning< def warn_scanf_nonzero_width : Warning< "zero field width in scanf format string is unused">, InGroup<Format>; +def warn_format_conversion_size_unsupported: Warning< + "format specifies %select{an exact-|a fastest-}0 width integer type with " + "invalid bit-width %1">, + InGroup<Format>; def warn_format_conversion_argument_type_mismatch : Warning< "format specifies type %0 but the argument has " "%select{type|underlying type}2 %1">, diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp index 88d0f1c98ed0d2f..39359c2b18fb499 100644 --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -297,18 +297,19 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS, if (I == E) return false; int s = 0; + bool MSVCRT = true; while (unsigned(*I - '0') <= 9) { + MSVCRT = false; s = 10 * s + unsigned(*I - '0'); ++I; } - // s == 0 is MSVCRT case, like l but only for c, C, s, S, or Z on windows - // s != 0 for b, d, i, o, u, x, or X when a size followed(like 8, 16, 32 or 64) - if (s != 0) { + // MSVCRT == true is MSVCRT case, like l but only for c, C, s, S, or Z on windows + // MSVCRT == false for b, d, i, o, u, x, or X when a size followed(like 8, 16, 32 or 64) + if (!MSVCRT) { std::set<int> supported_list {8, 16, 32, 64}; - if (supported_list.count(s) == 0) { - return false; - } + if (supported_list.count(s) == 0) + FS.setExplicitlyFixedSizeValid(false); FS.setExplicitlyFixedSize(s); } diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp index ad92fb3aab97d86..d4d9a0596620af1 100644 --- a/clang/lib/AST/PrintfFormatString.cpp +++ b/clang/lib/AST/PrintfFormatString.cpp @@ -560,9 +560,9 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, return ArgType::Invalid(); case LengthModifier::AsWide: case LengthModifier::AsWideFast: - int s = getExplicitlyFixedSize(); - bool fast = LM.getKind() == LengthModifier::AsWideFast ? true : false; - return clang::analyze_format_string::wToArgType(s, fast, Ctx); + int S = getExplicitlyFixedSize(); + bool FAST = LM.getKind() == LengthModifier::AsWideFast ? true : false; + return clang::analyze_format_string::wToArgType(S, FAST, Ctx); } if (CS.isUIntArg()) diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp index 6f856f1b0bedbd4..de261a303f322a6 100644 --- a/clang/lib/AST/ScanfFormatString.cpp +++ b/clang/lib/AST/ScanfFormatString.cpp @@ -265,9 +265,9 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { return ArgType::Invalid(); case LengthModifier::AsWide: case LengthModifier::AsWideFast: - int s = getExplicitlyFixedSize(); - bool fast = LM.getKind() == LengthModifier::AsWideFast ? true : false; - return clang::analyze_format_string::wToArgType(s, fast, Ctx); + int S = getExplicitlyFixedSize(); + bool FAST = LM.getKind() == LengthModifier::AsWideFast ? true : false; + return clang::analyze_format_string::wToArgType(S, FAST, Ctx); } llvm_unreachable("Unsupported LengthModifier Type"); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 77c8334f3ca25d3..7e2f5dc6708c4da 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -11680,6 +11680,17 @@ bool CheckPrintfHandler::HandlePrintfSpecifier( if (!FS.hasStandardConversionSpecifier(S.getLangOpts())) HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen); + // Check the explicitly fixed size is supported + if (!FS.isExplicitlyFixedSizeSupported()){ + EmitFormatDiagnostic(S.PDiag( + diag::warn_format_conversion_size_unsupported) + << FS.getLengthModifier().toString() + << FS.getExplicitlyFixedSize(), + getLocationOfByte(startSpecifier), + /*IsStringLocation*/true, + getSpecifierRange(startSpecifier, specifierLen)); + } + // The remaining checks depend on the data arguments. if (ArgPassingKind == Sema::FAPK_VAList) return true; @@ -12289,6 +12300,17 @@ bool CheckScanfHandler::HandleScanfSpecifier( else if (!FS.hasStandardLengthConversionCombination()) HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, diag::warn_format_non_standard_conversion_spec); + + // Check the explicitly fixed size is supported + if (!FS.isExplicitlyFixedSizeSupported()){ + EmitFormatDiagnostic(S.PDiag( + diag::warn_format_conversion_size_unsupported) + << FS.getLengthModifier().toString() + << FS.getExplicitlyFixedSize(), + getLocationOfByte(startSpecifier), + /*IsStringLocation*/true, + getSpecifierRange(startSpecifier, specifierLen)); + } if (!FS.hasStandardConversionSpecifier(S.getLangOpts())) HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen); diff --git a/clang/test/Sema/format-strings-ms.c b/clang/test/Sema/format-strings-ms.c index bca824533d128ae..e6172ee436114ef 100644 --- a/clang/test/Sema/format-strings-ms.c +++ b/clang/test/Sema/format-strings-ms.c @@ -101,6 +101,10 @@ void w_int_test(void) { scanf("%w16i", b); // expected-warning{{format specifies type 'short' but the argument has type 'int'}} scanf("%w32u", c); scanf("%w64x", d); + + // unsupported size + printf("%w92d", a); // expected-warning{{format specifies w width integer type with invalid bit-width 92}} + scanf("%w0i", b); // expected-warning{{format specifies w width integer type with invalid bit-width 0}} } void wf_test(void) { @@ -118,6 +122,10 @@ void wf_test(void) { scanf("%wf16u", b); scanf("%wf32o", c); scanf("%wf64X", d); + + // unsupported size + printf("%wf0d", a); // expected-warning{{format specifies wf width integer type with invalid bit-width 0}} + scanf("%wf35u", b); // expected-warning{{format specifies wf width integer type with invalid bit-width 35}} } #endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits