https://github.com/brad0 updated https://github.com/llvm/llvm-project/pull/120689
>From 5f01b45635d4fe6bb22161d2312dca0c0df86827 Mon Sep 17 00:00:00 2001 From: Brad Smith <b...@comstyle.com> Date: Thu, 19 Dec 2024 21:35:57 -0500 Subject: [PATCH] [clang][Sema] Fixes for %b printf extension handling The %b printf extension in the kernel is not fixed to a int type. On sparc64 there are various %llb formats. Adjust the code to handle the length specifiers and type check like it is used by the regular case. --- clang/include/clang/AST/FormatString.h | 8 +++-- clang/lib/AST/FormatString.cpp | 7 +++++ clang/lib/Sema/SemaChecking.cpp | 38 +++++++++++++++++------- clang/test/Sema/format-strings-freebsd.c | 8 ++++- 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/AST/FormatString.h b/clang/include/clang/AST/FormatString.h index a074dd23e2ad4c..8449affd177732 100644 --- a/clang/include/clang/AST/FormatString.h +++ b/clang/include/clang/AST/FormatString.h @@ -240,8 +240,12 @@ class ConversionSpecifier { bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) || kind == FreeBSDrArg || kind == FreeBSDyArg; } - bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; } - bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; } + bool isUIntArg() const { + return (kind >= UIntArgBeg && kind <= UIntArgEnd) || kind == FreeBSDbArg; + } + bool isAnyIntArg() const { + return (kind >= IntArgBeg && kind <= UIntArgEnd) || kind == FreeBSDbArg; + } bool isDoubleArg() const { return kind >= DoubleArgBeg && kind <= DoubleArgEnd; } diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp index e892c1592df986..47879e288918d0 100644 --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -879,6 +879,9 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target, case ConversionSpecifier::XArg: case ConversionSpecifier::nArg: return true; + case ConversionSpecifier::FreeBSDbArg: + return Target.getTriple().isOSFreeBSD() || + Target.getTriple().isPS() || Target.getTriple().isOSOpenBSD(); case ConversionSpecifier::FreeBSDrArg: case ConversionSpecifier::FreeBSDyArg: return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS(); @@ -919,6 +922,9 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target, case ConversionSpecifier::ScanListArg: case ConversionSpecifier::ZArg: return true; + case ConversionSpecifier::FreeBSDbArg: + return Target.getTriple().isOSFreeBSD() || + Target.getTriple().isPS() || Target.getTriple().isOSOpenBSD(); case ConversionSpecifier::FreeBSDrArg: case ConversionSpecifier::FreeBSDyArg: return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS(); @@ -1085,6 +1091,7 @@ bool FormatSpecifier::hasStandardLengthConversionCombination() const { case ConversionSpecifier::uArg: case ConversionSpecifier::xArg: case ConversionSpecifier::XArg: + case ConversionSpecifier::FreeBSDbArg: return false; default: return true; diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 881907ac311a30..e0714130c90937 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -7179,18 +7179,34 @@ bool CheckPrintfHandler::HandlePrintfSpecifier( // Claim the second argument. CoveredArgs.set(argIndex + 1); - // Type check the first argument (int for %b, pointer for %D) const Expr *Ex = getDataArg(argIndex); - const analyze_printf::ArgType &AT = - (CS.getKind() == ConversionSpecifier::FreeBSDbArg) ? - ArgType(S.Context.IntTy) : ArgType::CPointerTy; - if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType())) - EmitFormatDiagnostic( - S.PDiag(diag::warn_format_conversion_argument_type_mismatch) - << AT.getRepresentativeTypeName(S.Context) << Ex->getType() - << false << Ex->getSourceRange(), - Ex->getBeginLoc(), /*IsStringLocation*/ false, - getSpecifierRange(startSpecifier, specifierLen)); + if (CS.getKind() == ConversionSpecifier::FreeBSDDArg) { + // Type check the first argument (pointer for %D) + const analyze_printf::ArgType &AT = ArgType::CPointerTy; + if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType())) + EmitFormatDiagnostic( + S.PDiag(diag::warn_format_conversion_argument_type_mismatch) + << AT.getRepresentativeTypeName(S.Context) << Ex->getType() + << false << Ex->getSourceRange(), + Ex->getBeginLoc(), /*IsStringLocation*/ false, + getSpecifierRange(startSpecifier, specifierLen)); + } else { + // Check the length modifier for %b + if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(), + S.getLangOpts())) + HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, + diag::warn_format_nonsensical_length); + else if (!FS.hasStandardLengthModifier()) + HandleNonStandardLengthModifier(FS, startSpecifier, specifierLen); + else if (!FS.hasStandardLengthConversionCombination()) + HandleInvalidLengthModifier( + FS, CS, startSpecifier, specifierLen, + diag::warn_format_non_standard_conversion_spec); + + // Type check the first argument of %b + if (!checkFormatExpr(FS, startSpecifier, specifierLen, Ex)) + return false; + } // Type check the second argument (char * for both %b and %D) Ex = getDataArg(argIndex + 1); diff --git a/clang/test/Sema/format-strings-freebsd.c b/clang/test/Sema/format-strings-freebsd.c index 3d3ed6b40f48dc..3540dca2cfabcd 100644 --- a/clang/test/Sema/format-strings-freebsd.c +++ b/clang/test/Sema/format-strings-freebsd.c @@ -8,13 +8,19 @@ int freebsd_kernel_printf(const char *, ...) __attribute__((__format__(__freebsd void check_freebsd_kernel_extensions(int i, long l, char *s, short h) { - // %b expects an int and a char * + // %b expects a char * freebsd_kernel_printf("reg=%b\n", i, "\10\2BITTWO\1BITONE\n"); // no-warning freebsd_kernel_printf("reg=%b\n", l, "\10\2BITTWO\1BITONE\n"); // expected-warning{{format specifies type 'int' but the argument has type 'long'}} freebsd_kernel_printf("reg=%b\n", i, l); // expected-warning{{format specifies type 'char *' but the argument has type 'long'}} freebsd_kernel_printf("reg=%b\n", i); // expected-warning{{more '%' conversions than data arguments}} freebsd_kernel_printf("reg=%b\n", i, "\10\2BITTWO\1BITONE\n", l); // expected-warning{{data argument not used by format string}} + freebsd_kernel_printf("reg=%llb\n", i, "\10\2BITTWO\1BITONE\n"); // expected-warning{{format specifies type 'long long' but the argument has type 'int'}} + freebsd_kernel_printf("reg=%llb\n", ll, "\10\2BITTWO\1BITONE\n"); // no-warning + freebsd_kernel_printf("reg=%llb\n", ll, i); // expected-warning{{format specifies type 'char *' but the argument has type 'long long'}} + freebsd_kernel_printf("reg=%llb\n", ll); // expected-warning{{more '%' conversions than data arguments}} + freebsd_kernel_printf("reg=%llb\n", ll, "\10\2BITTWO\1BITONE\n", l); // expected-warning{{data argument not used by format string}} + // %D expects an unsigned char * and a char * freebsd_kernel_printf("%6D", s, ":"); // no-warning freebsd_kernel_printf("%6D", i, ":"); // expected-warning{{format specifies type 'void *' but the argument has type 'int'}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits