]> granicus.if.org Git - clang/commitdiff
Teach scanf/printf checking about '%Ld' and friends (a GNU extension). Fixes PR...
authorTed Kremenek <kremenek@apple.com>
Tue, 24 Jan 2012 21:29:54 +0000 (21:29 +0000)
committerTed Kremenek <kremenek@apple.com>
Tue, 24 Jan 2012 21:29:54 +0000 (21:29 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148859 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/FormatString.cpp
lib/Analysis/PrintfFormatString.cpp
lib/Analysis/ScanfFormatString.cpp
test/Sema/format-strings-scanf.c
test/Sema/format-strings.c

index fb52742bb0a5d88add4bf2758e6bd4f8b16fcd06..a4d97fd90af84333939b670083832c94b484083f 100644 (file)
@@ -548,6 +548,14 @@ bool FormatSpecifier::hasValidLengthModifier() const {
         case ConversionSpecifier::gArg:
         case ConversionSpecifier::GArg:
           return true;
+        // GNU extension.
+        case ConversionSpecifier::dArg:
+        case ConversionSpecifier::iArg:
+        case ConversionSpecifier::oArg:
+        case ConversionSpecifier::uArg:
+        case ConversionSpecifier::xArg:
+        case ConversionSpecifier::XArg:
+          return true;
         default:
           return false;
       }
index bc2b35693431a679aa7c25b0ddfe7528e70f66f8..dbe73c8f83d7df7fe948427bf3a9ae6210bbfa8a 100644 (file)
@@ -259,7 +259,8 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
   if (CS.isIntArg())
     switch (LM.getKind()) {
       case LengthModifier::AsLongDouble:
-        return ArgTypeResult::Invalid();
+        // GNU extension.
+        return Ctx.LongLongTy;
       case LengthModifier::None: return Ctx.IntTy;
       case LengthModifier::AsChar: return ArgTypeResult::AnyCharTy;
       case LengthModifier::AsShort: return Ctx.ShortTy;
@@ -280,7 +281,8 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
   if (CS.isUIntArg())
     switch (LM.getKind()) {
       case LengthModifier::AsLongDouble:
-        return ArgTypeResult::Invalid();
+        // GNU extension.
+        return Ctx.UnsignedLongLongTy;
       case LengthModifier::None: return Ctx.UnsignedIntTy;
       case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
       case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
index 38afd615c192b5435fb7f80b9443acc8429e67c0..c1cdef8632792a2b0cb8ddd3e8d71ea6e26e5232 100644 (file)
@@ -218,7 +218,9 @@ ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const {
           return ScanfArgTypeResult();
         case LengthModifier::AsPtrDiff:
           return ScanfArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t *");
-        case LengthModifier::AsLongDouble: return ScanfArgTypeResult::Invalid();
+        case LengthModifier::AsLongDouble:
+          // GNU extension.
+          return ArgTypeResult(Ctx.LongLongTy);
         case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid();
         case LengthModifier::AsMAllocate: return ScanfArgTypeResult::Invalid();
       }
@@ -242,7 +244,9 @@ ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const {
         case LengthModifier::AsPtrDiff:
           // FIXME: Unsigned version of ptrdiff_t?
           return ScanfArgTypeResult();
-        case LengthModifier::AsLongDouble: return ScanfArgTypeResult::Invalid();
+        case LengthModifier::AsLongDouble:
+          // GNU extension.
+          return ArgTypeResult(Ctx.UnsignedLongLongTy);
         case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid();
         case LengthModifier::AsMAllocate: return ScanfArgTypeResult::Invalid();
       }
index 6962a97611381f9f87182268508ed0684de7b7b6..d89dbc494b71d6c69345266cce9e1d18bf690034 100644 (file)
@@ -103,3 +103,13 @@ void test_alloc_extension(char **sp, wchar_t **lsp, float *fp) {
   scanf("%m[abc]", fp); // expected-warning{{format specifies type 'char **' but the argument has type 'float *'}}
 }
 
+void test_longlong(long long *x, unsigned long long *y) {
+  scanf("%Ld", y); // no-warning
+  scanf("%Lu", y); // no-warning
+  scanf("%Lx", y); // no-warning
+  scanf("%Ld", x); // no-warning
+  scanf("%Lu", x); // no-warning
+  scanf("%Lx", x); // no-warning
+  scanf("%Ls", "hello"); // expected-warning {{length modifier 'L' results in undefined behavior or no effect with 's' conversion specifier}}
+}
+
index e32ad245e37afeba756079138207037c27ebdf5e..9daaf3b0a51af4202fbbbf17e2a8fcbe5440ffda 100644 (file)
@@ -469,3 +469,14 @@ void pr9751() {
   // when the original string is within the argument expression.
   printf(1 ? "yes %d" : "no %d"); // expected-warning 2{{more '%' conversions than data arguments}}
 }
+
+// PR 9466: clang: doesn't know about %Lu, %Ld, and %Lx 
+void printf_longlong(long long x, unsigned long long y) {
+  printf("%Ld", y); // no-warning
+  printf("%Lu", y); // no-warning
+  printf("%Lx", y); // no-warning
+  printf("%Ld", x); // no-warning
+  printf("%Lu", x); // no-warning
+  printf("%Lx", x); // no-warning
+  printf("%Ls", "hello"); // expected-warning {{length modifier 'L' results in undefined behavior or no effect with 's' conversion specifier}}
+}