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

Reply via email to