[cfe-commits] r146326 - in /cfe/trunk: include/clang/Analysis/Analyses/FormatString.h lib/Analysis/ScanfFormatString.cpp lib/Sema/SemaChecking.cpp test/Analysis/taint-generic.c test/Analysis/taint-tester.c test/Sema/format-strings-fixit.c test/Sema/format-strings-int-typedefs.c test/Sema/format-strings-scanf.c

Hans Wennborg hans at hanshq.net
Sat Dec 10 05:20:12 PST 2011


Author: hans
Date: Sat Dec 10 07:20:11 2011
New Revision: 146326

URL: http://llvm.org/viewvc/llvm-project?rev=146326&view=rev
Log:
Check that arguments to a scanf call match the format specifier,
and offer fixits when there is a mismatch.

Modified:
    cfe/trunk/include/clang/Analysis/Analyses/FormatString.h
    cfe/trunk/lib/Analysis/ScanfFormatString.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/test/Analysis/taint-generic.c
    cfe/trunk/test/Analysis/taint-tester.c
    cfe/trunk/test/Sema/format-strings-fixit.c
    cfe/trunk/test/Sema/format-strings-int-typedefs.c
    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=146326&r1=146325&r2=146326&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/FormatString.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/FormatString.h Sat Dec 10 07:20:11 2011
@@ -185,6 +185,7 @@
     return EndScanList ? EndScanList - Position : 1;
   }
 
+  bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
   const char *toString() const;
 
   bool isPrintfKind() const { return IsPrintf; }
@@ -364,7 +365,6 @@
 
   bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
   bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; }
-  bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
   bool isDoubleArg() const { return kind >= DoubleArgBeg &&
                                     kind <= DoubleArgBeg; }
   unsigned getLength() const {
@@ -506,10 +506,35 @@
   }
 };
 
+using analyze_format_string::ArgTypeResult;
 using analyze_format_string::LengthModifier;
 using analyze_format_string::OptionalAmount;
 using analyze_format_string::OptionalFlag;
 
+class ScanfArgTypeResult : public ArgTypeResult {
+public:
+  enum Kind { UnknownTy, InvalidTy, CStrTy, WCStrTy, PtrToArgTypeResultTy };
+private:
+  Kind K;
+  ArgTypeResult A;
+  const char *Name;
+  QualType getRepresentativeType(ASTContext &C) const;
+public:
+  ScanfArgTypeResult(Kind k = UnknownTy, const char* n = 0) : K(k), Name(n) {}
+  ScanfArgTypeResult(ArgTypeResult a, const char *n = 0)
+      : K(PtrToArgTypeResultTy), A(a), Name(n) {
+    assert(A.isValid());
+  }
+
+  static ScanfArgTypeResult Invalid() { return ScanfArgTypeResult(InvalidTy); }
+
+  bool isValid() const { return K != InvalidTy; }
+
+  bool matchesType(ASTContext& C, QualType argTy) const;
+
+  std::string getRepresentativeTypeName(ASTContext& C) const;
+};
+
 class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
   OptionalFlag SuppressAssignment; // '*'
 public:
@@ -538,6 +563,12 @@
     return CS.consumesDataArgument() && !SuppressAssignment;
   }
 
+  ScanfArgTypeResult getArgType(ASTContext &Ctx) const;
+
+  bool fixType(QualType QT, const LangOptions &LangOpt);
+
+  void toString(raw_ostream &os) const;
+
   static ScanfSpecifier Parse(const char *beg, const char *end);
 };
 

Modified: cfe/trunk/lib/Analysis/ScanfFormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ScanfFormatString.cpp?rev=146326&r1=146325&r2=146326&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ScanfFormatString.cpp (original)
+++ cfe/trunk/lib/Analysis/ScanfFormatString.cpp Sat Dec 10 07:20:11 2011
@@ -20,9 +20,11 @@
 using clang::analyze_format_string::LengthModifier;
 using clang::analyze_format_string::OptionalAmount;
 using clang::analyze_format_string::ConversionSpecifier;
+using clang::analyze_scanf::ScanfArgTypeResult;
 using clang::analyze_scanf::ScanfConversionSpecifier;
 using clang::analyze_scanf::ScanfSpecifier;
 using clang::UpdateOnReturn;
+using namespace clang;
 
 typedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier>
         ScanfSpecifierResult;
@@ -190,7 +192,213 @@
   }
   return ScanfSpecifierResult(Start, FS);
 }
-  
+
+ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const {
+  const ScanfConversionSpecifier &CS = getConversionSpecifier();
+
+  if (!CS.consumesDataArgument())
+    return ScanfArgTypeResult::Invalid();
+
+  switch(CS.getKind()) {
+    // Signed int.
+    case ConversionSpecifier::dArg:
+    case ConversionSpecifier::iArg:
+      switch (LM.getKind()) {
+        case LengthModifier::None: return ArgTypeResult(Ctx.IntTy);
+        case LengthModifier::AsChar:
+          return ArgTypeResult(ArgTypeResult::AnyCharTy);
+        case LengthModifier::AsShort: return ArgTypeResult(Ctx.ShortTy);
+        case LengthModifier::AsLong: return ArgTypeResult(Ctx.LongTy);
+        case LengthModifier::AsLongLong: return ArgTypeResult(Ctx.LongLongTy);
+        case LengthModifier::AsIntMax:
+          return ScanfArgTypeResult(Ctx.getIntMaxType(), "intmax_t *");
+        case LengthModifier::AsSizeT:
+          // FIXME: ssize_t.
+          return ScanfArgTypeResult();
+        case LengthModifier::AsPtrDiff:
+          return ScanfArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t *");
+        case LengthModifier::AsLongDouble: return ScanfArgTypeResult::Invalid();
+      }
+
+    // Unsigned int.
+    case ConversionSpecifier::oArg:
+    case ConversionSpecifier::uArg:
+    case ConversionSpecifier::xArg:
+    case ConversionSpecifier::XArg:
+      switch (LM.getKind()) {
+        case LengthModifier::None: return ArgTypeResult(Ctx.UnsignedIntTy);
+        case LengthModifier::AsChar: return ArgTypeResult(Ctx.UnsignedCharTy);
+        case LengthModifier::AsShort: return ArgTypeResult(Ctx.UnsignedShortTy);
+        case LengthModifier::AsLong: return ArgTypeResult(Ctx.UnsignedLongTy);
+        case LengthModifier::AsLongLong:
+          return ArgTypeResult(Ctx.UnsignedLongLongTy);
+        case LengthModifier::AsIntMax:
+          return ScanfArgTypeResult(Ctx.getUIntMaxType(), "uintmax_t *");
+        case LengthModifier::AsSizeT:
+          return ScanfArgTypeResult(Ctx.getSizeType(), "size_t *");
+        case LengthModifier::AsPtrDiff:
+          // FIXME: Unsigned version of ptrdiff_t?
+          return ScanfArgTypeResult();
+        case LengthModifier::AsLongDouble: return ScanfArgTypeResult::Invalid();
+      }
+
+    // Float.
+    case ConversionSpecifier::aArg:
+    case ConversionSpecifier::AArg:
+    case ConversionSpecifier::eArg:
+    case ConversionSpecifier::EArg:
+    case ConversionSpecifier::fArg:
+    case ConversionSpecifier::FArg:
+    case ConversionSpecifier::gArg:
+    case ConversionSpecifier::GArg:
+      switch (LM.getKind()) {
+        case LengthModifier::None: return ArgTypeResult(Ctx.FloatTy);
+        case LengthModifier::AsLong: return ArgTypeResult(Ctx.DoubleTy);
+        case LengthModifier::AsLongDouble:
+          return ArgTypeResult(Ctx.LongDoubleTy);
+        default:
+          return ScanfArgTypeResult::Invalid();
+      }
+
+    // Char, string and scanlist.
+    case ConversionSpecifier::cArg:
+    case ConversionSpecifier::sArg:
+    case ConversionSpecifier::ScanListArg:
+      switch (LM.getKind()) {
+        case LengthModifier::None: return ScanfArgTypeResult::CStrTy;
+        case LengthModifier::AsLong:
+          return ScanfArgTypeResult(ScanfArgTypeResult::WCStrTy, "wchar_t *");
+        default:
+          return ScanfArgTypeResult::Invalid();
+      }
+    case ConversionSpecifier::CArg:
+    case ConversionSpecifier::SArg:
+      // FIXME: Mac OS X specific?
+      return ScanfArgTypeResult(ScanfArgTypeResult::WCStrTy, "wchar_t *");
+
+    // Pointer.
+    case ConversionSpecifier::pArg:
+      return ScanfArgTypeResult(ArgTypeResult(ArgTypeResult::CPointerTy));
+
+    default:
+      break;
+  }
+
+  return ScanfArgTypeResult();
+}
+
+bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt)
+{
+  if (!QT->isPointerType())
+    return false;
+
+  QualType PT = QT->getPointeeType();
+  const BuiltinType *BT = PT->getAs<BuiltinType>();
+  if (!BT)
+    return false;
+
+  // Pointer to a character.
+  if (PT->isAnyCharacterType()) {
+    CS.setKind(ConversionSpecifier::sArg);
+    if (PT->isWideCharType())
+      LM.setKind(LengthModifier::AsWideChar);
+    else
+      LM.setKind(LengthModifier::None);
+    return true;
+  }
+
+  // Figure out the length modifier.
+  switch (BT->getKind()) {
+    // no modifier
+    case BuiltinType::UInt:
+    case BuiltinType::Int:
+    case BuiltinType::Float:
+      LM.setKind(LengthModifier::None);
+      break;
+
+    // hh
+    case BuiltinType::Char_U:
+    case BuiltinType::UChar:
+    case BuiltinType::Char_S:
+    case BuiltinType::SChar:
+      LM.setKind(LengthModifier::AsChar);
+      break;
+
+    // h
+    case BuiltinType::Short:
+    case BuiltinType::UShort:
+      LM.setKind(LengthModifier::AsShort);
+      break;
+
+    // l
+    case BuiltinType::Long:
+    case BuiltinType::ULong:
+    case BuiltinType::Double:
+      LM.setKind(LengthModifier::AsLong);
+      break;
+
+    // ll
+    case BuiltinType::LongLong:
+    case BuiltinType::ULongLong:
+      LM.setKind(LengthModifier::AsLongLong);
+      break;
+
+    // L
+    case BuiltinType::LongDouble:
+      LM.setKind(LengthModifier::AsLongDouble);
+      break;
+
+    // Don't know.
+    default:
+      return false;
+  }
+
+  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
+  if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus0x)) {
+    const IdentifierInfo *Identifier = QT.getBaseTypeIdentifier();
+    if (Identifier->getName() == "size_t") {
+      LM.setKind(LengthModifier::AsSizeT);
+    } else if (Identifier->getName() == "ssize_t") {
+      // Not C99, but common in Unix.
+      LM.setKind(LengthModifier::AsSizeT);
+    } else if (Identifier->getName() == "intmax_t") {
+      LM.setKind(LengthModifier::AsIntMax);
+    } else if (Identifier->getName() == "uintmax_t") {
+      LM.setKind(LengthModifier::AsIntMax);
+    } else if (Identifier->getName() == "ptrdiff_t") {
+      LM.setKind(LengthModifier::AsPtrDiff);
+    }
+  }
+
+  // Figure out the conversion specifier.
+  if (PT->isRealFloatingType())
+    CS.setKind(ConversionSpecifier::fArg);
+  else if (PT->isSignedIntegerType())
+    CS.setKind(ConversionSpecifier::dArg);
+  else if (PT->isUnsignedIntegerType()) {
+    // Preserve the original formatting, e.g. 'X', 'o'.
+    if (!CS.isUIntArg()) {
+      CS.setKind(ConversionSpecifier::uArg);
+    }
+  } else
+    llvm_unreachable("Unexpected type");
+
+  return true;
+}
+
+void ScanfSpecifier::toString(raw_ostream &os) const {
+  os << "%";
+
+  if (usesPositionalArg())
+    os << getPositionalArgIndex() << "$";
+  if (SuppressAssignment)
+    os << "*";
+
+  FieldWidth.toString(os);
+  os << LM.toString();
+  os << CS.toString();
+}
+
 bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
                                                     const char *I,
                                                     const char *E) {
@@ -218,4 +426,47 @@
   return false;
 }
 
+bool ScanfArgTypeResult::matchesType(ASTContext& C, QualType argTy) const {
+  switch (K) {
+    case InvalidTy:
+      llvm_unreachable("ArgTypeResult must be valid");
+    case UnknownTy:
+      return true;
+    case CStrTy:
+      return ArgTypeResult(ArgTypeResult::CStrTy).matchesType(C, argTy);
+    case WCStrTy:
+      return ArgTypeResult(ArgTypeResult::WCStrTy).matchesType(C, argTy);
+    case PtrToArgTypeResultTy: {
+      const PointerType *PT = argTy->getAs<PointerType>();
+      if (!PT)
+        return false;
+      return A.matchesType(C, PT->getPointeeType());
+    }
+  }
 
+  return false; // Unreachable, but we still get a warning.
+}
+
+QualType ScanfArgTypeResult::getRepresentativeType(ASTContext &C) const {
+  switch (K) {
+    case InvalidTy:
+      llvm_unreachable("No representative type for Invalid ArgTypeResult");
+    case UnknownTy:
+      return QualType();
+    case CStrTy:
+      return C.getPointerType(C.CharTy);
+    case WCStrTy:
+      return C.getPointerType(C.getWCharType());
+    case PtrToArgTypeResultTy:
+      return C.getPointerType(A.getRepresentativeType(C));
+  }
+
+  return QualType(); // Not reachable.
+}
+
+std::string ScanfArgTypeResult::getRepresentativeTypeName(ASTContext& C) const {
+  std::string S = getRepresentativeType(C).getAsString();
+  if (!Name)
+    return std::string("'") + S + "'";
+  return std::string("'") + Name + "' (aka '" + S + "')";
+}

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=146326&r1=146325&r2=146326&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Sat Dec 10 07:20:11 2011
@@ -2371,8 +2371,38 @@
   if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
     return false;
   
-  // FIXME: Check that the argument type matches the format specifier.
-  
+  // Check that the argument type matches the format specifier.
+  const Expr *Ex = getDataArg(argIndex);
+  const analyze_scanf::ScanfArgTypeResult &ATR = FS.getArgType(S.Context);
+  if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) {
+    ScanfSpecifier fixedFS = FS;
+    bool success = fixedFS.fixType(Ex->getType(), S.getLangOptions());
+
+    if (success) {
+      // Get the fix string from the fixed format specifier.
+      llvm::SmallString<128> buf;
+      llvm::raw_svector_ostream os(buf);
+      fixedFS.toString(os);
+
+      EmitFormatDiagnostic(
+        S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
+          << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
+          << Ex->getSourceRange(),
+        getLocationOfByte(CS.getStart()),
+        /*IsStringLocation*/true,
+        getSpecifierRange(startSpecifier, specifierLen),
+        FixItHint::CreateReplacement(
+          getSpecifierRange(startSpecifier, specifierLen),
+          os.str()));
+    } else {
+      S.Diag(getLocationOfByte(CS.getStart()),
+             diag::warn_printf_conversion_argument_type_mismatch)
+          << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
+          << getSpecifierRange(startSpecifier, specifierLen)
+          << Ex->getSourceRange();
+    }
+  }
+
   return true;
 }
 

Modified: cfe/trunk/test/Analysis/taint-generic.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/taint-generic.c?rev=146326&r1=146325&r2=146326&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/taint-generic.c (original)
+++ cfe/trunk/test/Analysis/taint-generic.c Sat Dec 10 07:20:11 2011
@@ -39,7 +39,8 @@
 
 void scanfArg() {
   int t;
-  scanf("%d", t); // expected-warning {{Pointer argument is expected}}
+  scanf("%d", t); // expected-warning {{Pointer argument is expected}} \
+                  // expected-warning {{conversion specifies type 'int *' but the argument has type 'int'}}
 }
 
 void bufferGetchar(int x) {

Modified: cfe/trunk/test/Analysis/taint-tester.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/taint-tester.c?rev=146326&r1=146325&r2=146326&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/taint-tester.c (original)
+++ cfe/trunk/test/Analysis/taint-tester.c Sat Dec 10 07:20:11 2011
@@ -49,8 +49,8 @@
 
   // Taint on fields of a struct.
   struct XYStruct xy = {2, 3, 11};
-  scanf("%f", &xy.y);
-  scanf("%f", &xy.x);
+  scanf("%d", &xy.y);
+  scanf("%d", &xy.x);
   int tx = xy.x; // expected-warning {{tainted}}
   int ty = xy.y; // FIXME: This should be tainted as well.
   char ntz = xy.z;// no warning

Modified: cfe/trunk/test/Sema/format-strings-fixit.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings-fixit.c?rev=146326&r1=146325&r2=146326&view=diff
==============================================================================
--- cfe/trunk/test/Sema/format-strings-fixit.c (original)
+++ cfe/trunk/test/Sema/format-strings-fixit.c Sat Dec 10 07:20:11 2011
@@ -10,6 +10,11 @@
 
 int printf(char const *, ...);
 
+typedef __SIZE_TYPE__ size_t;
+typedef __INTMAX_TYPE__ intmax_t;
+typedef __UINTMAX_TYPE__ uintmax_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+
 void test() {
   // Basic types
   printf("%s", (int) 123);
@@ -47,11 +52,6 @@
   unsigned long val = 42;
   printf("%X", val);
 
-  typedef __SIZE_TYPE__ size_t;
-  typedef __INTMAX_TYPE__ intmax_t;
-  typedef __UINTMAX_TYPE__ uintmax_t;
-  typedef __PTRDIFF_TYPE__ ptrdiff_t;
-
   // size_t, etc.
   printf("%f", (size_t) 42);
   printf("%f", (intmax_t) 42);
@@ -62,6 +62,51 @@
   printf("%ld", "foo");
 }
 
+int scanf(char const *, ...);
+
+void test2() {
+  char str[100];
+  short shortVar;
+  unsigned short uShortVar;
+  int intVar;
+  unsigned uIntVar;
+  float floatVar;
+  double doubleVar;
+  long double longDoubleVar;
+  long longVar;
+  unsigned long uLongVar;
+  long long longLongVar;
+  unsigned long long uLongLongVar;
+  size_t sizeVar;
+  intmax_t intmaxVar;
+  uintmax_t uIntmaxVar;
+  ptrdiff_t ptrdiffVar;
+
+  scanf("%lf", str);
+  scanf("%f", &shortVar);
+  scanf("%f", &uShortVar);
+  scanf("%p", &intVar);
+  scanf("%Lf", &uIntVar);
+  scanf("%ld", &floatVar);
+  scanf("%f", &doubleVar);
+  scanf("%d", &longDoubleVar);
+  scanf("%f", &longVar);
+  scanf("%f", &uLongVar);
+  scanf("%f", &longLongVar);
+  scanf("%f", &uLongLongVar);
+
+  // Some named ints.
+  scanf("%f", &sizeVar);
+  scanf("%f", &intmaxVar);
+  scanf("%f", &uIntmaxVar);
+  scanf("%f", &ptrdiffVar);
+
+  // Perserve the original formatting for unsigned integers.
+  scanf("%o", &uLongVar);
+  scanf("%x", &uLongVar);
+  scanf("%X", &uLongVar);
+}
+
 // Validate the fixes...
 // CHECK: printf("%d", (int) 123);
 // CHECK: printf("abc%s", "testing testing 123");
@@ -87,3 +132,23 @@
 // CHECK: printf("%ju", (uintmax_t) 42);
 // CHECK: printf("%td", (ptrdiff_t) 42);
 // CHECK: printf("%s", "foo");
+
+// CHECK: scanf("%s", str);
+// CHECK: scanf("%hd", &shortVar);
+// CHECK: scanf("%hu", &uShortVar);
+// CHECK: scanf("%d", &intVar);
+// CHECK: scanf("%u", &uIntVar);
+// CHECK: scanf("%f", &floatVar);
+// CHECK: scanf("%lf", &doubleVar);
+// CHECK: scanf("%Lf", &longDoubleVar);
+// CHECK: scanf("%ld", &longVar);
+// CHECK: scanf("%lu", &uLongVar);
+// CHECK: scanf("%lld", &longLongVar);
+// CHECK: scanf("%llu", &uLongLongVar);
+// CHECK: scanf("%zu", &sizeVar);
+// CHECK: scanf("%jd", &intmaxVar);
+// CHECK: scanf("%ju", &uIntmaxVar);
+// CHECK: scanf("%td", &ptrdiffVar);
+// CHECK: scanf("%lo", &uLongVar);
+// CHECK: scanf("%lx", &uLongVar);
+// CHECK: scanf("%lX", &uLongVar);

Modified: cfe/trunk/test/Sema/format-strings-int-typedefs.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings-int-typedefs.c?rev=146326&r1=146325&r2=146326&view=diff
==============================================================================
--- cfe/trunk/test/Sema/format-strings-int-typedefs.c (original)
+++ cfe/trunk/test/Sema/format-strings-int-typedefs.c Sat Dec 10 07:20:11 2011
@@ -1,6 +1,7 @@
 // RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
 
 int printf(char const *, ...);
+int scanf(char const *, ...);
 
 void test(void) {
   printf("%jd", 42.0); // expected-warning {{conversion specifies type 'intmax_t' (aka 'long long')}}
@@ -12,6 +13,15 @@
   printf("%S", 42.0);  // expected-warning {{conversion specifies type 'wchar_t *' (aka 'int *')}}
   printf("%C", 42.0);  // expected-warning {{conversion specifies type 'wchar_t' (aka 'int')}}
 
+  scanf("%jd", 0); // expected-warning {{conversion specifies type 'intmax_t *' (aka 'long long *')}}
+  scanf("%ju", 0); // expected-warning {{conversion specifies type 'uintmax_t *' (aka 'unsigned long long *')}}
+  scanf("%zu", 0); // expected-warning {{conversion specifies type 'size_t *' (aka 'unsigned long *')}}
+  scanf("%td", 0); // expected-warning {{conversion specifies type 'ptrdiff_t *' (aka 'int *')}}
+  scanf("%lc", 0); // expected-warning {{conversion specifies type 'wchar_t *' (aka 'int *')}}
+  scanf("%ls", 0); // expected-warning {{conversion specifies type 'wchar_t *' (aka 'int *')}}
+  scanf("%S",  0);  // expected-warning {{conversion specifies type 'wchar_t *' (aka 'int *')}}
+  scanf("%C",  0);  // expected-warning {{conversion specifies type 'wchar_t *' (aka 'int *')}}
+
 
   // typedef size_t et al. to something crazy.
   typedef void *size_t;

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=146326&r1=146325&r2=146326&view=diff
==============================================================================
--- cfe/trunk/test/Sema/format-strings-scanf.c (original)
+++ cfe/trunk/test/Sema/format-strings-scanf.c Sat Dec 10 07:20:11 2011
@@ -28,7 +28,7 @@
 
 void bad_length_modifiers(char *s, void *p, wchar_t *ws, long double *ld) {
   scanf("%hhs", "foo"); // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 's' conversion specifier}}
-  scanf("%1$zp", p); // expected-warning{{length modifier 'z' results in undefined behavior or no effect with 'p' conversion specifier}}
+  scanf("%1$zp", &p); // expected-warning{{length modifier 'z' results in undefined behavior or no effect with 'p' conversion specifier}}
   scanf("%ls", ws); // no-warning
   scanf("%#.2Lf", ld); // expected-warning{{invalid conversion specifier '#'}}
 }
@@ -37,10 +37,11 @@
 // format string is somewhere else, point to it in a note.
 void pr9751() {
   int *i;
+  char str[100];
   const char kFormat1[] = "%00d"; // expected-note{{format string is defined here}}}
   scanf(kFormat1, i); // expected-warning{{zero field width in scanf format string is unused}}
   scanf("%00d", i); // expected-warning{{zero field width in scanf format string is unused}}
   const char kFormat2[] = "%["; // expected-note{{format string is defined here}}}
-  scanf(kFormat2, &i); // expected-warning{{no closing ']' for '%[' in scanf format string}}
-  scanf("%[", &i); // expected-warning{{no closing ']' for '%[' in scanf format string}}
+  scanf(kFormat2, str); // expected-warning{{no closing ']' for '%[' in scanf format string}}
+  scanf("%[", str); // expected-warning{{no closing ']' for '%[' in scanf format string}}
 }





More information about the cfe-commits mailing list