]> granicus.if.org Git - clang/commitdiff
Don't warn when a '%%' or '%*d' (scanf) is used in a format string with positional...
authorTed Kremenek <kremenek@apple.com>
Mon, 19 Jul 2010 22:01:06 +0000 (22:01 +0000)
committerTed Kremenek <kremenek@apple.com>
Mon, 19 Jul 2010 22:01:06 +0000 (22:01 +0000)
these don't actually consume an argument.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@108757 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Analysis/Analyses/FormatString.h
lib/Sema/SemaChecking.cpp
test/Sema/format-strings-scanf.c
test/Sema/format-strings.c

index f79300df9f9130a3955028aa5422f69269d19e28..d76e4f7ad03755a6fbe271f4cd3691fd8f9ef275 100644 (file)
@@ -220,17 +220,14 @@ public:
   void setUsesPositionalArg() { UsesPositionalArg = true; }
 
   void setArgIndex(unsigned i) {
-      // assert(CS.consumesDataArgument());
     argIndex = i;
   }
 
   unsigned getArgIndex() const {
-      //assert(CS.consumesDataArgument());
     return argIndex;
   }
 
   unsigned getPositionalArgIndex() const {
-      //assert(CS.consumesDataArgument());
     return argIndex + 1;
   }
 
@@ -402,12 +399,16 @@ public:
   const OptionalAmount &getPrecision() const {
     return Precision;
   }
+  
+  bool consumesDataArgument() const {
+    return CS.consumesDataArgument();
+  }
 
-    /// \brief Returns the builtin type that a data argument
-    /// paired with this format specifier should have.  This method
-    /// will return null if the format specifier does not have
-    /// a matching data argument or the matching argument matches
-    /// more than one type.
+  /// \brief Returns the builtin type that a data argument
+  /// paired with this format specifier should have.  This method
+  /// will return null if the format specifier does not have
+  /// a matching data argument or the matching argument matches
+  /// more than one type.
   ArgTypeResult getArgType(ASTContext &Ctx) const;
 
   const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
index f36a9ed938677c1d2effb6ea9293df4284d2ec88..72939e6e592d93715d8ead375bbf218beb0daa34 100644 (file)
@@ -1434,16 +1434,18 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
   using namespace analyze_printf;  
   const ConversionSpecifier &CS = FS.getConversionSpecifier();
 
-  if (atFirstArg) {
-    atFirstArg = false;
-    usesPositionalArgs = FS.usesPositionalArg();
-  }
-  else if (usesPositionalArgs != FS.usesPositionalArg()) {
-    // Cannot mix-and-match positional and non-positional arguments.
-    S.Diag(getLocationOfByte(CS.getStart()),
-           diag::warn_format_mix_positional_nonpositional_args)
-      << getSpecifierRange(startSpecifier, specifierLen);
-    return false;
+  if (FS.consumesDataArgument()) {
+    if (atFirstArg) {
+        atFirstArg = false;
+        usesPositionalArgs = FS.usesPositionalArg();
+    }
+    else if (usesPositionalArgs != FS.usesPositionalArg()) {
+      // Cannot mix-and-match positional and non-positional arguments.
+      S.Diag(getLocationOfByte(CS.getStart()),
+             diag::warn_format_mix_positional_nonpositional_args)
+        << getSpecifierRange(startSpecifier, specifierLen);
+      return false;
+    }
   }
 
   // First check if the field width, precision, and conversion specifier
@@ -1653,18 +1655,20 @@ bool CheckScanfHandler::HandleScanfSpecifier(
 
   const ConversionSpecifier &CS = FS.getConversionSpecifier();
 
-  // FIXME: Handle case where '%' and '*' don't consume an argument.
-  // This needs to be done for the printf case as well.
-  if (atFirstArg) {
-    atFirstArg = false;
-    usesPositionalArgs = FS.usesPositionalArg();
-  }
-  else if (usesPositionalArgs != FS.usesPositionalArg()) {
-    // Cannot mix-and-match positional and non-positional arguments.
-    S.Diag(getLocationOfByte(CS.getStart()),
-           diag::warn_format_mix_positional_nonpositional_args)
-      << getSpecifierRange(startSpecifier, specifierLen);
-    return false;
+  // Handle case where '%' and '*' don't consume an argument.  These shouldn't
+  // be used to decide if we are using positional arguments consistently.
+  if (FS.consumesDataArgument()) {
+    if (atFirstArg) {
+      atFirstArg = false;
+      usesPositionalArgs = FS.usesPositionalArg();
+    }
+    else if (usesPositionalArgs != FS.usesPositionalArg()) {
+      // Cannot mix-and-match positional and non-positional arguments.
+      S.Diag(getLocationOfByte(CS.getStart()),
+             diag::warn_format_mix_positional_nonpositional_args)
+        << getSpecifierRange(startSpecifier, specifierLen);
+      return false;
+    }
   }
   
   // Check if the field with is non-zero.
index 5d2a7a7a9b21e62544049c0c874023c95b9b0fd4..68552b3e241953316eac099b4827be2c19b73225 100644 (file)
@@ -16,4 +16,11 @@ void test(const char *s, int *i) {
   unsigned short s_x;
   scanf ("%" "hu" "\n", &s_x); // no-warning
   scanf("%y", i); // expected-warning{{invalid conversion specifier 'y'}}
+  scanf("%%"); // no-warning
+  scanf("%%%1$d", i); // no-warning
+  scanf("%1$d%%", i); // no-warning
+  scanf("%d", i, i); // expected-warning{{data argument not used by format string}}
+  scanf("%*d", i); // // expected-warning{{data argument not used by format string}}
+  scanf("%*d", i); // // expected-warning{{data argument not used by format string}}
+  scanf("%*d%1$d", i); // no-warning
 }
index c6dee6801e80e0c23851e89472186cd4adc30468..080e4dbeb528abf6bda8440f1f35b226ef5c2dd1 100644 (file)
@@ -239,6 +239,8 @@ void test_positional_arguments() {
   printf("%1$2.2d", (int) 2); // no-warning
   printf("%2$*1$.2d", (int) 2, (int) 3); // no-warning
   printf("%2$*8$d", (int) 2, (int) 3); // expected-warning{{specified field width is missing a matching 'int' argument}}
+  printf("%%%1$d", (int) 2); // no-warning
+  printf("%1$d%%", (int) 2); // no-warning
 }
 
 // PR 6697 - Handle format strings where the data argument is not adjacent to the format string