[cfe-commits] r146649 - in /cfe/trunk: include/clang/Analysis/Analyses/FormatString.h lib/Analysis/FormatString.cpp lib/Analysis/FormatStringParsing.h lib/Analysis/PrintfFormatString.cpp lib/Analysis/ScanfFormatString.cpp lib/Sema/SemaChecking.cpp test/Sema/format-strings-c90.c test/Sema/format-strings-scanf.c

Hans Wennborg hans at hanshq.net
Thu Dec 15 02:25:47 PST 2011


Author: hans
Date: Thu Dec 15 04:25:47 2011
New Revision: 146649

URL: http://llvm.org/viewvc/llvm-project?rev=146649&view=rev
Log:
Support the 'a' length modifier in scanf format strings as a C90
extension.

This fixes gcc.dg/format/c90-scanf-3.c and ext-4.c (test for excess
errors).

Added:
    cfe/trunk/test/Sema/format-strings-c90.c
Modified:
    cfe/trunk/include/clang/Analysis/Analyses/FormatString.h
    cfe/trunk/lib/Analysis/FormatString.cpp
    cfe/trunk/lib/Analysis/FormatStringParsing.h
    cfe/trunk/lib/Analysis/PrintfFormatString.cpp
    cfe/trunk/lib/Analysis/ScanfFormatString.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/test/Sema/format-strings-scanf.c

Modified: cfe/trunk/include/clang/Analysis/Analyses/FormatString.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/FormatString.h?rev=146649&r1=146648&r2=146649&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/FormatString.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/FormatString.h Thu Dec 15 04:25:47 2011
@@ -71,6 +71,7 @@
     AsSizeT,      // 'z'
     AsPtrDiff,    // 't'
     AsLongDouble, // 'L'
+    AsAllocate,    // for '%as', GNU extension to C90 scanf
     AsWideChar = AsLong // for '%ls', only makes sense for printf
   };
 
@@ -630,10 +631,10 @@
 };
 
 bool ParsePrintfString(FormatStringHandler &H,
-                       const char *beg, const char *end);
+                       const char *beg, const char *end, const LangOptions &LO);
 
 bool ParseScanfString(FormatStringHandler &H,
-                       const char *beg, const char *end);
+                      const char *beg, const char *end, const LangOptions &LO);
 
 } // end analyze_format_string namespace
 } // end clang namespace

Modified: cfe/trunk/lib/Analysis/FormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/FormatString.cpp?rev=146649&r1=146648&r2=146649&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/FormatString.cpp (original)
+++ cfe/trunk/lib/Analysis/FormatString.cpp Thu Dec 15 04:25:47 2011
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "FormatStringParsing.h"
+#include "clang/Basic/LangOptions.h"
 
 using clang::analyze_format_string::ArgTypeResult;
 using clang::analyze_format_string::FormatStringHandler;
@@ -175,7 +176,9 @@
 bool
 clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
                                                   const char *&I,
-                                                  const char *E) {
+                                                  const char *E,
+                                                  const LangOptions &LO,
+                                                  bool IsScanf) {
   LengthModifier::Kind lmKind = LengthModifier::None;
   const char *lmPosition = I;
   switch (*I) {
@@ -196,6 +199,19 @@
     case 't': lmKind = LengthModifier::AsPtrDiff;    ++I; break;
     case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
     case 'q': lmKind = LengthModifier::AsLongLong;   ++I; break;
+    case 'a':
+      if (IsScanf && !LO.C99 && !LO.CPlusPlus) {
+        // For scanf in C90, look at the next character to see if this should
+        // be parsed as the GNU extension 'a' length modifier. If not, this
+        // will be parsed as a conversion specifier.
+        ++I;
+        if (I != E && (*I == 's' || *I == 'S' || *I == '[')) {
+          lmKind = LengthModifier::AsAllocate;
+          break;
+        }
+        --I;
+      }
+      return false;
   }
   LengthModifier lm(lmPosition, lmKind);
   FS.setLengthModifier(lm);
@@ -391,6 +407,8 @@
     return "t";
   case AsLongDouble:
     return "L";
+  case AsAllocate:
+    return "a";
   case None:
     return "";
   }
@@ -527,6 +545,15 @@
         default:
           return false;
       }
+
+    case LengthModifier::AsAllocate:
+      switch (CS.getKind()) {
+        case ConversionSpecifier::sArg:
+        case ConversionSpecifier::SArg:
+          return true;
+        default:
+          return false;
+      }
   }
   return false;
 }

Modified: cfe/trunk/lib/Analysis/FormatStringParsing.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/FormatStringParsing.h?rev=146649&r1=146648&r2=146649&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/FormatStringParsing.h (original)
+++ cfe/trunk/lib/Analysis/FormatStringParsing.h Thu Dec 15 04:25:47 2011
@@ -8,6 +8,8 @@
 
 namespace clang {
 
+class LangOptions;
+
 template <typename T>
 class UpdateOnReturn {
   T &ValueToUpdate;
@@ -42,7 +44,8 @@
 
 /// Returns true if a LengthModifier was parsed and installed in the
 /// FormatSpecifier& argument, and false otherwise.
-bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const char *E);
+bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const char *E,
+                         const LangOptions &LO, bool IsScanf = false);
   
 template <typename T> class SpecifierResult {
   T FS;
@@ -69,4 +72,3 @@
 } // end clang namespace
 
 #endif
-

Modified: cfe/trunk/lib/Analysis/PrintfFormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PrintfFormatString.cpp?rev=146649&r1=146648&r2=146649&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/PrintfFormatString.cpp (original)
+++ cfe/trunk/lib/Analysis/PrintfFormatString.cpp Thu Dec 15 04:25:47 2011
@@ -51,7 +51,8 @@
 static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
                                                   const char *&Beg,
                                                   const char *E,
-                                                  unsigned &argIndex) {
+                                                  unsigned &argIndex,
+                                                  const LangOptions &LO) {
 
   using namespace clang::analyze_format_string;
   using namespace clang::analyze_printf;
@@ -150,7 +151,7 @@
   }
 
   // Look for the length modifier.
-  if (ParseLengthModifier(FS, I, E) && I == E) {
+  if (ParseLengthModifier(FS, I, E, LO) && I == E) {
     // No more characters left?
     H.HandleIncompleteSpecifier(Start, E - Start);
     return true;
@@ -210,13 +211,15 @@
 
 bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
                                                      const char *I,
-                                                     const char *E) {
+                                                     const char *E,
+                                                     const LangOptions &LO) {
 
   unsigned argIndex = 0;
 
   // Keep looking for a format specifier until we have exhausted the string.
   while (I != E) {
-    const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex);
+    const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
+                                                            LO);
     // Did a fail-stop error of any kind occur when parsing the specifier?
     // If so, don't do any more processing.
     if (FSR.shouldStop())
@@ -269,6 +272,8 @@
         return ArgTypeResult();
       case LengthModifier::AsPtrDiff:
         return ArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t");
+      case LengthModifier::AsAllocate:
+        return ArgTypeResult::Invalid();
     }
 
   if (CS.isUIntArg())
@@ -288,6 +293,8 @@
         // FIXME: How to get the corresponding unsigned
         // version of ptrdiff_t?
         return ArgTypeResult();
+      case LengthModifier::AsAllocate:
+        return ArgTypeResult::Invalid();
     }
 
   if (CS.isDoubleArg()) {

Modified: cfe/trunk/lib/Analysis/ScanfFormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ScanfFormatString.cpp?rev=146649&r1=146648&r2=146649&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ScanfFormatString.cpp (original)
+++ cfe/trunk/lib/Analysis/ScanfFormatString.cpp Thu Dec 15 04:25:47 2011
@@ -67,7 +67,8 @@
 static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
                                                 const char *&Beg,
                                                 const char *E,
-                                                unsigned &argIndex) {
+                                                unsigned &argIndex,
+                                                const LangOptions &LO) {
   
   using namespace clang::analyze_scanf;
   const char *I = Beg;
@@ -132,7 +133,7 @@
   }
   
   // Look for the length modifier.
-  if (ParseLengthModifier(FS, I, E) && I == E) {
+  if (ParseLengthModifier(FS, I, E, LO, /*scanf=*/true) && I == E) {
       // No more characters left?
     H.HandleIncompleteSpecifier(Start, E - Start);
     return true;
@@ -218,6 +219,7 @@
         case LengthModifier::AsPtrDiff:
           return ScanfArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t *");
         case LengthModifier::AsLongDouble: return ScanfArgTypeResult::Invalid();
+        case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid();
       }
 
     // Unsigned int.
@@ -240,6 +242,7 @@
           // FIXME: Unsigned version of ptrdiff_t?
           return ScanfArgTypeResult();
         case LengthModifier::AsLongDouble: return ScanfArgTypeResult::Invalid();
+        case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid();
       }
 
     // Float.
@@ -274,7 +277,9 @@
     case ConversionSpecifier::CArg:
     case ConversionSpecifier::SArg:
       // FIXME: Mac OS X specific?
-      return ScanfArgTypeResult(ScanfArgTypeResult::WCStrTy, "wchar_t *");
+      if (LM.getKind() == LengthModifier::None)
+        return ScanfArgTypeResult(ScanfArgTypeResult::WCStrTy, "wchar_t *");
+      return ScanfArgTypeResult::Invalid();
 
     // Pointer.
     case ConversionSpecifier::pArg:
@@ -401,13 +406,15 @@
 
 bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
                                                     const char *I,
-                                                    const char *E) {
+                                                    const char *E,
+                                                    const LangOptions &LO) {
   
   unsigned argIndex = 0;
   
   // Keep looking for a format specifier until we have exhausted the string.
   while (I != E) {
-    const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex);
+    const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex,
+                                                          LO);
     // Did a fail-stop error of any kind occur when parsing the specifier?
     // If so, don't do any more processing.
     if (FSR.shouldStop())

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=146649&r1=146648&r2=146649&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Thu Dec 15 04:25:47 2011
@@ -2442,7 +2442,8 @@
                          Str, HasVAListArg, TheCall, format_idx,
                          inFunctionCall);
   
-    if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen))
+    if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
+                                                  getLangOptions()))
       H.DoneProcessing();
   }
   else {
@@ -2451,7 +2452,8 @@
                         Str, HasVAListArg, TheCall, format_idx,
                         inFunctionCall);
     
-    if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen))
+    if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen,
+                                                 getLangOptions()))
       H.DoneProcessing();
   }
 }

Added: cfe/trunk/test/Sema/format-strings-c90.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings-c90.c?rev=146649&view=auto
==============================================================================
--- cfe/trunk/test/Sema/format-strings-c90.c (added)
+++ cfe/trunk/test/Sema/format-strings-c90.c Thu Dec 15 04:25:47 2011
@@ -0,0 +1,21 @@
+/* RUN: %clang_cc1 -fsyntax-only -verify -pedantic -std=c89 %s
+ */
+
+int scanf(const char * restrict, ...);
+int printf(const char *restrict, ...);
+
+void foo(char **sp, float *fp, int *ip) {
+  /* TODO: Warn that the 'a' length modifier is an extension. */
+  scanf("%as", sp);
+
+  /* TODO: Warn that the 'a' conversion specifier is a C99 feature. */
+  scanf("%a", fp);
+  scanf("%afoobar", fp);
+  printf("%a", 1.0);
+  printf("%as", 1.0);
+  printf("%aS", 1.0);
+  printf("%a[", 1.0);
+  printf("%afoo", 1.0);
+
+  scanf("%da", ip);
+}

Modified: cfe/trunk/test/Sema/format-strings-scanf.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings-scanf.c?rev=146649&r1=146648&r2=146649&view=diff
==============================================================================
--- cfe/trunk/test/Sema/format-strings-scanf.c (original)
+++ cfe/trunk/test/Sema/format-strings-scanf.c Thu Dec 15 04:25:47 2011
@@ -67,3 +67,12 @@
   vfscanf(f, "%[abc", ap); // expected-warning{{no closing ']' for '%[' in scanf format string}}
   vsscanf(buf, "%[abc", ap); // expected-warning{{no closing ']' for '%[' in scanf format string}}
 }
+
+void test_alloc_extension(char **sp, wchar_t **lsp) {
+  /* Make sure "%a" gets parsed as a conversion specifier for float,
+   * even when followed by an 's', 'S' or '[', which would cause it to be
+   * parsed as a length modifier in C90. */
+  scanf("%as", sp); // expected-warning{{conversion specifies type 'float *' but the argument has type 'char **'}}
+  scanf("%aS", lsp); // expected-warning{{conversion specifies type 'float *' but the argument has type 'wchar_t **' (aka 'int **')}}
+  scanf("%a[bcd]", sp); // expected-warning{{conversion specifies type 'float *' but the argument has type 'char **'}}
+}





More information about the cfe-commits mailing list