]> granicus.if.org Git - clang/commitdiff
Properly check length modfiers for %n in format strings.
authorHans Wennborg <hans@hanshq.net>
Tue, 7 Aug 2012 09:13:19 +0000 (09:13 +0000)
committerHans Wennborg <hans@hanshq.net>
Tue, 7 Aug 2012 09:13:19 +0000 (09:13 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161408 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 0a30328b12b30e0ddbaa1df933f61aa8ac5bf515..9e4c0fec4c0473e6ee973ef0c5e23e17b866d52f 100644 (file)
@@ -312,6 +312,33 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
     return Ctx.DoubleTy;
   }
 
+  if (CS.getKind() == ConversionSpecifier::nArg) {
+    switch (LM.getKind()) {
+      case LengthModifier::None:
+        return ArgType::PtrTo(Ctx.IntTy);
+      case LengthModifier::AsChar:
+        return ArgType::PtrTo(Ctx.SignedCharTy);
+      case LengthModifier::AsShort:
+        return ArgType::PtrTo(Ctx.ShortTy);
+      case LengthModifier::AsLong:
+        return ArgType::PtrTo(Ctx.LongTy);
+      case LengthModifier::AsLongLong:
+      case LengthModifier::AsQuad:
+        return ArgType::PtrTo(Ctx.LongLongTy);
+      case LengthModifier::AsIntMax:
+        return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
+      case LengthModifier::AsSizeT:
+        return ArgType(); // FIXME: ssize_t
+      case LengthModifier::AsPtrDiff:
+        return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
+      case LengthModifier::AsLongDouble:
+        return ArgType(); // FIXME: Is this a known extension?
+      case LengthModifier::AsAllocate:
+      case LengthModifier::AsMAllocate:
+        return ArgType::Invalid();
+    }
+  }
+
   switch (CS.getKind()) {
     case ConversionSpecifier::sArg:
       if (LM.getKind() == LengthModifier::AsWideChar) {
@@ -330,8 +357,6 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
       return ArgType(Ctx.WCharTy, "wchar_t");
     case ConversionSpecifier::pArg:
       return ArgType::CPointerTy;
-    case ConversionSpecifier::nArg:
-      return ArgType::PtrTo(Ctx.IntTy);
     case ConversionSpecifier::ObjCObjArg:
       return ArgType::ObjCPointerTy;
     default:
index 80deb37fad24e6b87f40c57dc86001f798cb8938..2942400621d1a18517a70c2eb251fee5386d50b5 100644 (file)
@@ -318,7 +318,30 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
 
     // Write-back.
     case ConversionSpecifier::nArg:
-      return ArgType::PtrTo(Ctx.IntTy);
+      switch (LM.getKind()) {
+        case LengthModifier::None:
+          return ArgType::PtrTo(Ctx.IntTy);
+        case LengthModifier::AsChar:
+          return ArgType::PtrTo(Ctx.SignedCharTy);
+        case LengthModifier::AsShort:
+          return ArgType::PtrTo(Ctx.ShortTy);
+        case LengthModifier::AsLong:
+          return ArgType::PtrTo(Ctx.LongTy);
+        case LengthModifier::AsLongLong:
+        case LengthModifier::AsQuad:
+          return ArgType::PtrTo(Ctx.LongLongTy);
+        case LengthModifier::AsIntMax:
+          return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
+        case LengthModifier::AsSizeT:
+          return ArgType(); // FIXME: ssize_t
+        case LengthModifier::AsPtrDiff:
+          return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
+        case LengthModifier::AsLongDouble:
+          return ArgType(); // FIXME: Is this a known extension?
+        case LengthModifier::AsAllocate:
+        case LengthModifier::AsMAllocate:
+          return ArgType::Invalid();
+        }
 
     default:
       break;
index 49c97149a77f683fe0e77acc6b9dbedc8b1de9ae..235ac11faa1c0744c6539f0b6e3cc2c9400f918c 100644 (file)
@@ -131,6 +131,32 @@ void test_quad(int *x, long long *llx) {
 void test_writeback(int *x) {
   scanf("%n", (void*)0); // expected-warning{{format specifies type 'int *' but the argument has type 'void *'}}
   scanf("%n %c", x, x); // expected-warning{{format specifies type 'char *' but the argument has type 'int *'}}
+
+  scanf("%hhn", (signed char*)0); // no-warning
+  scanf("%hhn", (char*)0); // no-warning
+  scanf("%hhn", (unsigned char*)0); // no-warning
+  scanf("%hhn", (int*)0); // expected-warning{{format specifies type 'signed char *' but the argument has type 'int *'}}
+
+  scanf("%hn", (short*)0); // no-warning
+  scanf("%hn", (unsigned short*)0); // no-warning
+  scanf("%hn", (int*)0); // expected-warning{{format specifies type 'short *' but the argument has type 'int *'}}
+
+  scanf("%n", (int*)0); // no-warning
+  scanf("%n", (unsigned int*)0); // no-warning
+  scanf("%n", (char*)0); // expected-warning{{format specifies type 'int *' but the argument has type 'char *'}}
+
+  scanf("%ln", (long*)0); // no-warning
+  scanf("%ln", (unsigned long*)0); // no-warning
+  scanf("%ln", (int*)0); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}
+
+  scanf("%lln", (long long*)0); // no-warning
+  scanf("%lln", (unsigned long long*)0); // no-warning
+  scanf("%lln", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}
+
+  scanf("%qn", (long long*)0); // no-warning
+  scanf("%qn", (unsigned long long*)0); // no-warning
+  scanf("%qn", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}
+
 }
 
 void test_qualifiers(const int *cip, volatile int* vip,
index 7f88ff38c302490daa328102eeb26dedba2ec9a3..5058a762183d39ae3e5fb083f3b3790f2c62b16c 100644 (file)
@@ -13,3 +13,16 @@ void test(void) {
   // ptrdiff_t
   printf("%td", (double)42); // expected-warning {{format specifies type 'ptrdiff_t' (aka 'long') but the argument has type 'double'}}
 }
+
+void test_writeback(void) {
+  printf("%jn", (long*)0); // no-warning
+  printf("%jn", (unsigned long*)0); // no-warning
+  printf("%jn", (int*)0); // expected-warning{{format specifies type 'intmax_t *' (aka 'long *') but the argument has type 'int *'}}
+
+  printf("%zn", (long*)0); // no-warning
+  // FIXME: Warn about %zn with non-ssize_t argument.
+
+  printf("%tn", (long*)0); // no-warning
+  printf("%tn", (unsigned long*)0); // no-warning
+  printf("%tn", (int*)0); // expected-warning{{format specifies type 'ptrdiff_t *' (aka 'long *') but the argument has type 'int *'}}
+}
index aff996fed3ee41438d218b821937a610bad98ae7..86b9296108c6e632596419c4a7a2cb91602b3c16 100644 (file)
@@ -90,6 +90,33 @@ void check_writeback_specifier()
   char *b;
   printf("%n", b); // expected-warning{{format specifies type 'int *' but the argument has type 'char *'}}
   printf("%n", &x); // no-warning
+
+  printf("%hhn", (signed char*)0); // no-warning
+  printf("%hhn", (char*)0); // no-warning
+  printf("%hhn", (unsigned char*)0); // no-warning
+  printf("%hhn", (int*)0); // expected-warning{{format specifies type 'signed char *' but the argument has type 'int *'}}
+
+  printf("%hn", (short*)0); // no-warning
+  printf("%hn", (unsigned short*)0); // no-warning
+  printf("%hn", (int*)0); // expected-warning{{format specifies type 'short *' but the argument has type 'int *'}}
+
+  printf("%n", (int*)0); // no-warning
+  printf("%n", (unsigned int*)0); // no-warning
+  printf("%n", (char*)0); // expected-warning{{format specifies type 'int *' but the argument has type 'char *'}}
+
+  printf("%ln", (long*)0); // no-warning
+  printf("%ln", (unsigned long*)0); // no-warning
+  printf("%ln", (int*)0); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}
+
+  printf("%lln", (long long*)0); // no-warning
+  printf("%lln", (unsigned long long*)0); // no-warning
+  printf("%lln", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}
+
+  printf("%qn", (long long*)0); // no-warning
+  printf("%qn", (unsigned long long*)0); // no-warning
+  printf("%qn", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}
+
+  printf("%Ln", 0); // expected-warning{{length modifier 'L' results in undefined behavior or no effect with 'n' conversion specifier}}
 }
 
 void check_invalid_specifier(FILE* fp, char *buf)