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

Hans Wennborg hans at hanshq.net
Tue Aug 7 01:59:46 PDT 2012


Author: hans
Date: Tue Aug  7 03:59:46 2012
New Revision: 161407

URL: http://llvm.org/viewvc/llvm-project?rev=161407&view=rev
Log:
Remove ScanfArgType and bake that logic into ArgType.

This is useful for example for %n in printf, which expects
a pointer to int with the same logic for checking as %d
would have in scanf.

Modified:
    cfe/trunk/include/clang/Analysis/Analyses/FormatString.h
    cfe/trunk/lib/Analysis/FormatString.cpp
    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=161407&r1=161406&r2=161407&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/FormatString.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/FormatString.h Tue Aug  7 03:59:46 2012
@@ -209,15 +209,24 @@
   const Kind K;
   QualType T;
   const char *Name;
+  bool Ptr;
 public:
-  ArgType(Kind k = UnknownTy, const char *n = 0) : K(k), Name(n) {}
-  ArgType(QualType t, const char *n = 0) : K(SpecificTy), T(t), Name(n)  {}
-  ArgType(CanQualType t) : K(SpecificTy), T(t), Name(0) {}
+  ArgType(Kind k = UnknownTy, const char *n = 0) : K(k), Name(n), Ptr(false) {}
+  ArgType(QualType t, const char *n = 0)
+      : K(SpecificTy), T(t), Name(n), Ptr(false) {}
+  ArgType(CanQualType t) : K(SpecificTy), T(t), Name(0), Ptr(false) {}
 
   static ArgType Invalid() { return ArgType(InvalidTy); }
-
   bool isValid() const { return K != InvalidTy; }
 
+  /// Create an ArgType which corresponds to the type pointer to A.
+  static ArgType PtrTo(const ArgType& A) {
+    assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
+    ArgType Res = A;
+    Res.Ptr = true;
+    return Res;
+  }
+
   bool matchesType(ASTContext &C, QualType argTy) const;
 
   QualType getRepresentativeType(ASTContext &C) const;
@@ -517,30 +526,6 @@
 using analyze_format_string::OptionalAmount;
 using analyze_format_string::OptionalFlag;
 
-class ScanfArgType : public ArgType {
-public:
-  enum Kind { UnknownTy, InvalidTy, CStrTy, WCStrTy, PtrToArgTypeTy };
-private:
-  Kind K;
-  ArgType A;
-  const char *Name;
-  QualType getRepresentativeType(ASTContext &C) const;
-public:
-  ScanfArgType(Kind k = UnknownTy, const char* n = 0) : K(k), Name(n) {}
-  ScanfArgType(ArgType a, const char *n = 0)
-      : K(PtrToArgTypeTy), A(a), Name(n) {
-    assert(A.isValid());
-  }
-
-  static ScanfArgType Invalid() { return ScanfArgType(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:
@@ -569,7 +554,7 @@
     return CS.consumesDataArgument() && !SuppressAssignment;
   }
 
-  ScanfArgType getArgType(ASTContext &Ctx) const;
+  ArgType getArgType(ASTContext &Ctx) const;
 
   bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx);
 

Modified: cfe/trunk/lib/Analysis/FormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/FormatString.cpp?rev=161407&r1=161406&r2=161407&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/FormatString.cpp (original)
+++ cfe/trunk/lib/Analysis/FormatString.cpp Tue Aug  7 03:59:46 2012
@@ -233,6 +233,19 @@
 //===----------------------------------------------------------------------===//
 
 bool ArgType::matchesType(ASTContext &C, QualType argTy) const {
+  if (Ptr) {
+    // It has to be a pointer.
+    const PointerType *PT = argTy->getAs<PointerType>();
+    if (!PT)
+      return false;
+
+    // We cannot write through a const qualified pointer.
+    if (PT->getPointeeType().isConstQualified())
+      return false;
+
+    argTy = PT->getPointeeType();
+  }
+
   switch (K) {
     case InvalidTy:
       llvm_unreachable("ArgType must be valid");
@@ -262,13 +275,6 @@
         argTy = ETy->getDecl()->getIntegerType();
       argTy = C.getCanonicalType(argTy).getUnqualifiedType();
 
-      if (const PointerType *PTy = argTy->getAs<PointerType>()) {
-        // Strip volatile qualifier from pointee type.
-        QualType Pointee = PTy->getPointeeType();
-        Pointee.removeLocalVolatile();
-        argTy = C.getPointerType(Pointee);
-      }
-
       if (T == argTy)
         return true;
       // Check for "compatible types".
@@ -375,35 +381,59 @@
 }
 
 QualType ArgType::getRepresentativeType(ASTContext &C) const {
+  QualType Res;
   switch (K) {
     case InvalidTy:
       llvm_unreachable("No representative type for Invalid ArgType");
     case UnknownTy:
-      return QualType();
+      llvm_unreachable("No representative type for Unknown ArgType");
     case AnyCharTy:
-      return C.CharTy;
+      Res = C.CharTy;
+      break;
     case SpecificTy:
-      return T;
+      Res = T;
+      break;
     case CStrTy:
-      return C.getPointerType(C.CharTy);
+      Res = C.getPointerType(C.CharTy);
+      break;
     case WCStrTy:
-      return C.getPointerType(C.getWCharType());
+      Res = C.getPointerType(C.getWCharType());
+      break;
     case ObjCPointerTy:
-      return C.ObjCBuiltinIdTy;
+      Res = C.ObjCBuiltinIdTy;
+      break;
     case CPointerTy:
-      return C.VoidPtrTy;
+      Res = C.VoidPtrTy;
+      break;
     case WIntTy: {
-      return C.getWIntType();
+      Res = C.getWIntType();
+      break;
     }
   }
 
-  llvm_unreachable("Invalid ArgType Kind!");
+  if (Ptr)
+    Res = C.getPointerType(Res);
+  return Res;
 }
 
 std::string ArgType::getRepresentativeTypeName(ASTContext &C) const {
   std::string S = getRepresentativeType(C).getAsString();
-  if (Name && S != Name)
-    return std::string("'") + Name + "' (aka '" + S + "')";
+
+  std::string Alias;
+  if (Name) {
+    // Use a specific name for this type, e.g. "size_t".
+    Alias = Name;
+    if (Ptr) {
+      // If ArgType is actually a pointer to T, append an asterisk.
+      Alias += (Alias[Alias.size()-1] == '*') ? "*" : " *";
+    }
+    // If Alias is the same as the underlying type, e.g. wchar_t, then drop it.
+    if (S == Alias)
+      Alias.clear();
+  }
+
+  if (!Alias.empty())
+    return std::string("'") + Alias + "' (aka '" + S + "')";
   return std::string("'") + S + "'";
 }
 

Modified: cfe/trunk/lib/Analysis/PrintfFormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PrintfFormatString.cpp?rev=161407&r1=161406&r2=161407&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/PrintfFormatString.cpp (original)
+++ cfe/trunk/lib/Analysis/PrintfFormatString.cpp Tue Aug  7 03:59:46 2012
@@ -331,7 +331,7 @@
     case ConversionSpecifier::pArg:
       return ArgType::CPointerTy;
     case ConversionSpecifier::nArg:
-      return Ctx.getPointerType(Ctx.IntTy);
+      return ArgType::PtrTo(Ctx.IntTy);
     case ConversionSpecifier::ObjCObjArg:
       return ArgType::ObjCPointerTy;
     default:

Modified: cfe/trunk/lib/Analysis/ScanfFormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ScanfFormatString.cpp?rev=161407&r1=161406&r2=161407&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ScanfFormatString.cpp (original)
+++ cfe/trunk/lib/Analysis/ScanfFormatString.cpp Tue Aug  7 03:59:46 2012
@@ -20,7 +20,6 @@
 using clang::analyze_format_string::LengthModifier;
 using clang::analyze_format_string::OptionalAmount;
 using clang::analyze_format_string::ConversionSpecifier;
-using clang::analyze_scanf::ScanfArgType;
 using clang::analyze_scanf::ScanfConversionSpecifier;
 using clang::analyze_scanf::ScanfSpecifier;
 using clang::UpdateOnReturn;
@@ -194,37 +193,42 @@
   return ScanfSpecifierResult(Start, FS);
 }
 
-ScanfArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
+ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
   const ScanfConversionSpecifier &CS = getConversionSpecifier();
 
   if (!CS.consumesDataArgument())
-    return ScanfArgType::Invalid();
+    return ArgType::Invalid();
 
   switch(CS.getKind()) {
     // Signed int.
     case ConversionSpecifier::dArg:
     case ConversionSpecifier::iArg:
       switch (LM.getKind()) {
-        case LengthModifier::None: return ArgType(Ctx.IntTy);
+        case LengthModifier::None:
+          return ArgType::PtrTo(Ctx.IntTy);
         case LengthModifier::AsChar:
-          return ArgType(ArgType::AnyCharTy);
-        case LengthModifier::AsShort: return ArgType(Ctx.ShortTy);
-        case LengthModifier::AsLong: return ArgType(Ctx.LongTy);
+          return ArgType::PtrTo(ArgType::AnyCharTy);
+        case LengthModifier::AsShort:
+          return ArgType::PtrTo(Ctx.ShortTy);
+        case LengthModifier::AsLong:
+          return ArgType::PtrTo(Ctx.LongTy);
         case LengthModifier::AsLongLong:
         case LengthModifier::AsQuad:
-          return ArgType(Ctx.LongLongTy);
+          return ArgType::PtrTo(Ctx.LongLongTy);
         case LengthModifier::AsIntMax:
-          return ScanfArgType(Ctx.getIntMaxType(), "intmax_t *");
+          return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
         case LengthModifier::AsSizeT:
           // FIXME: ssize_t.
-          return ScanfArgType();
+          return ArgType();
         case LengthModifier::AsPtrDiff:
-          return ScanfArgType(Ctx.getPointerDiffType(), "ptrdiff_t *");
+          return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
         case LengthModifier::AsLongDouble:
           // GNU extension.
-          return ArgType(Ctx.LongLongTy);
-        case LengthModifier::AsAllocate: return ScanfArgType::Invalid();
-        case LengthModifier::AsMAllocate: return ScanfArgType::Invalid();
+          return ArgType::PtrTo(Ctx.LongLongTy);
+        case LengthModifier::AsAllocate:
+          return ArgType::Invalid();
+        case LengthModifier::AsMAllocate:
+          return ArgType::Invalid();
       }
 
     // Unsigned int.
@@ -233,25 +237,31 @@
     case ConversionSpecifier::xArg:
     case ConversionSpecifier::XArg:
       switch (LM.getKind()) {
-        case LengthModifier::None: return ArgType(Ctx.UnsignedIntTy);
-        case LengthModifier::AsChar: return ArgType(Ctx.UnsignedCharTy);
-        case LengthModifier::AsShort: return ArgType(Ctx.UnsignedShortTy);
-        case LengthModifier::AsLong: return ArgType(Ctx.UnsignedLongTy);
+        case LengthModifier::None:
+          return ArgType::PtrTo(Ctx.UnsignedIntTy);
+        case LengthModifier::AsChar:
+          return ArgType::PtrTo(Ctx.UnsignedCharTy);
+        case LengthModifier::AsShort:
+          return ArgType::PtrTo(Ctx.UnsignedShortTy);
+        case LengthModifier::AsLong:
+          return ArgType::PtrTo(Ctx.UnsignedLongTy);
         case LengthModifier::AsLongLong:
         case LengthModifier::AsQuad:
-          return ArgType(Ctx.UnsignedLongLongTy);
+          return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
         case LengthModifier::AsIntMax:
-          return ScanfArgType(Ctx.getUIntMaxType(), "uintmax_t *");
+          return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t"));
         case LengthModifier::AsSizeT:
-          return ScanfArgType(Ctx.getSizeType(), "size_t *");
+          return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));
         case LengthModifier::AsPtrDiff:
           // FIXME: Unsigned version of ptrdiff_t?
-          return ScanfArgType();
+          return ArgType();
         case LengthModifier::AsLongDouble:
           // GNU extension.
-          return ArgType(Ctx.UnsignedLongLongTy);
-        case LengthModifier::AsAllocate: return ScanfArgType::Invalid();
-        case LengthModifier::AsMAllocate: return ScanfArgType::Invalid();
+          return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
+        case LengthModifier::AsAllocate:
+          return ArgType::Invalid();
+        case LengthModifier::AsMAllocate:
+          return ArgType::Invalid();
       }
 
     // Float.
@@ -264,12 +274,14 @@
     case ConversionSpecifier::gArg:
     case ConversionSpecifier::GArg:
       switch (LM.getKind()) {
-        case LengthModifier::None: return ArgType(Ctx.FloatTy);
-        case LengthModifier::AsLong: return ArgType(Ctx.DoubleTy);
+        case LengthModifier::None:
+          return ArgType::PtrTo(Ctx.FloatTy);
+        case LengthModifier::AsLong:
+          return ArgType::PtrTo(Ctx.DoubleTy);
         case LengthModifier::AsLongDouble:
-          return ArgType(Ctx.LongDoubleTy);
+          return ArgType::PtrTo(Ctx.LongDoubleTy);
         default:
-          return ScanfArgType::Invalid();
+          return ArgType::Invalid();
       }
 
     // Char, string and scanlist.
@@ -277,40 +289,42 @@
     case ConversionSpecifier::sArg:
     case ConversionSpecifier::ScanListArg:
       switch (LM.getKind()) {
-        case LengthModifier::None: return ScanfArgType::CStrTy;
+        case LengthModifier::None:
+          return ArgType::PtrTo(ArgType::AnyCharTy);
         case LengthModifier::AsLong:
-          return ScanfArgType(ScanfArgType::WCStrTy, "wchar_t *");
+          return ArgType::PtrTo(ArgType(Ctx.getWCharType(), "wchar_t"));
         case LengthModifier::AsAllocate:
         case LengthModifier::AsMAllocate:
-          return ScanfArgType(ArgType::CStrTy);
+          return ArgType::PtrTo(ArgType::CStrTy);
         default:
-          return ScanfArgType::Invalid();
+          return ArgType::Invalid();
       }
     case ConversionSpecifier::CArg:
     case ConversionSpecifier::SArg:
       // FIXME: Mac OS X specific?
       switch (LM.getKind()) {
         case LengthModifier::None:
-          return ScanfArgType(ScanfArgType::WCStrTy, "wchar_t *");
+          return ArgType::PtrTo(ArgType(Ctx.getWCharType(), "wchar_t"));
         case LengthModifier::AsAllocate:
         case LengthModifier::AsMAllocate:
-          return ScanfArgType(ArgType::WCStrTy, "wchar_t **");
+          return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
         default:
-          return ScanfArgType::Invalid();
+          return ArgType::Invalid();
       }
 
     // Pointer.
     case ConversionSpecifier::pArg:
-      return ScanfArgType(ArgType(ArgType::CPointerTy));
+      return ArgType::PtrTo(ArgType::CPointerTy);
 
+    // Write-back.
     case ConversionSpecifier::nArg:
-      return ArgType(Ctx.IntTy);
+      return ArgType::PtrTo(Ctx.IntTy);
 
     default:
       break;
   }
 
-  return ScanfArgType();
+  return ArgType();
 }
 
 bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
@@ -393,8 +407,8 @@
     namedTypeToLengthModifier(PT, LM);
 
   // If fixing the length modifier was enough, we are done.
-  const analyze_scanf::ScanfArgType &ATR = getArgType(Ctx);
-  if (hasValidLengthModifier() && ATR.isValid() && ATR.matchesType(Ctx, QT))
+  const analyze_scanf::ArgType &AT = getArgType(Ctx);
+  if (hasValidLengthModifier() && AT.isValid() && AT.matchesType(Ctx, QT))
     return true;
 
   // Figure out the conversion specifier.
@@ -451,54 +465,3 @@
   assert(I == E && "Format string not exhausted");
   return false;
 }
-
-bool ScanfArgType::matchesType(ASTContext& C, QualType argTy) const {
-  // It has to be a pointer type.
-  const PointerType *PT = argTy->getAs<PointerType>();
-  if (!PT)
-    return false;
-
-  // We cannot write through a const qualified pointer.
-  if (PT->getPointeeType().isConstQualified())
-    return false;
-
-  switch (K) {
-    case InvalidTy:
-      llvm_unreachable("ArgType must be valid");
-    case UnknownTy:
-      return true;
-    case CStrTy:
-      return ArgType(ArgType::CStrTy).matchesType(C, argTy);
-    case WCStrTy:
-      return ArgType(ArgType::WCStrTy).matchesType(C, argTy);
-    case PtrToArgTypeTy: {
-      return A.matchesType(C, PT->getPointeeType());
-    }
-  }
-
-  llvm_unreachable("Invalid ScanfArgType Kind!");
-}
-
-QualType ScanfArgType::getRepresentativeType(ASTContext &C) const {
-  switch (K) {
-    case InvalidTy:
-      llvm_unreachable("No representative type for Invalid ArgType");
-    case UnknownTy:
-      return QualType();
-    case CStrTy:
-      return C.getPointerType(C.CharTy);
-    case WCStrTy:
-      return C.getPointerType(C.getWCharType());
-    case PtrToArgTypeTy:
-      return C.getPointerType(A.getRepresentativeType(C));
-  }
-
-  llvm_unreachable("Invalid ScanfArgType Kind!");
-}
-
-std::string ScanfArgType::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=161407&r1=161406&r2=161407&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Tue Aug  7 03:59:46 2012
@@ -2800,8 +2800,8 @@
   if (!Ex)
     return true;
 
-  const analyze_scanf::ScanfArgType &ATR = FS.getArgType(S.Context);
-  if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) {
+  const analyze_format_string::ArgType &AT = FS.getArgType(S.Context);
+  if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType())) {
     ScanfSpecifier fixedFS = FS;
     bool success = fixedFS.fixType(Ex->getType(), S.getLangOpts(),
                                    S.Context);
@@ -2814,7 +2814,7 @@
 
       EmitFormatDiagnostic(
         S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
-          << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
+          << AT.getRepresentativeTypeName(S.Context) << Ex->getType()
           << Ex->getSourceRange(),
         Ex->getLocStart(),
         /*IsStringLocation*/false,
@@ -2825,7 +2825,7 @@
     } else {
       EmitFormatDiagnostic(
         S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
-          << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
+          << AT.getRepresentativeTypeName(S.Context) << Ex->getType()
           << Ex->getSourceRange(),
         Ex->getLocStart(),
         /*IsStringLocation*/false,

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=161407&r1=161406&r2=161407&view=diff
==============================================================================
--- cfe/trunk/test/Sema/format-strings-scanf.c (original)
+++ cfe/trunk/test/Sema/format-strings-scanf.c Tue Aug  7 03:59:46 2012
@@ -33,6 +33,12 @@
   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
+
+  scanf("%s", (char*)0); // no-warning
+  scanf("%s", (volatile char*)0); // no-warning
+  scanf("%s", (signed char*)0); // no-warning
+  scanf("%s", (unsigned char*)0); // no-warning
+  scanf("%hhu", (signed char*)0); // no-warning
 }
 
 void bad_length_modifiers(char *s, void *p, wchar_t *ws, long double *ld) {





More information about the cfe-commits mailing list