[cfe-commits] r96310 - in /cfe/trunk: include/clang/Analysis/Analyses/PrintfFormatString.h lib/Analysis/PrintfFormatString.cpp lib/Sema/SemaChecking.cpp test/Sema/block-printf-attribute-1.c test/Sema/format-strings.c

Ted Kremenek kremenek at apple.com
Mon Feb 15 17:47:00 PST 2010


Author: kremenek
Date: Mon Feb 15 19:46:59 2010
New Revision: 96310

URL: http://llvm.org/viewvc/llvm-project?rev=96310&view=rev
Log:
Refactor the logic for printf argument type-checking into analyze_printf::ArgTypeResult.
Implement printf argument type checking for '%s'.

Fixes <rdar://problem/3065808>.

Modified:
    cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h
    cfe/trunk/lib/Analysis/PrintfFormatString.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/test/Sema/block-printf-attribute-1.c
    cfe/trunk/test/Sema/format-strings.c

Modified: cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h?rev=96310&r1=96309&r2=96310&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h Mon Feb 15 19:46:59 2010
@@ -18,11 +18,39 @@
 #include "clang/AST/CanonicalType.h"
 
 namespace clang {
-    
+
 class ASTContext;
-  
+
 namespace analyze_printf {
 
+class ArgTypeResult {
+public:
+  enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CStrTy,
+              WCStrTy };
+private:
+  const Kind K;
+  QualType T;
+  ArgTypeResult(bool) : K(InvalidTy) {}
+public:
+  ArgTypeResult(Kind k = UnknownTy) : K(k) {}
+  ArgTypeResult(QualType t) : K(SpecificTy), T(t) {}
+  ArgTypeResult(CanQualType t) : K(SpecificTy), T(t) {}
+
+  static ArgTypeResult Invalid() { return ArgTypeResult(true); }
+
+  bool isValid() const { return K != InvalidTy; }
+
+  const QualType *getSpecificType() const {
+    return K == SpecificTy ? &T : 0;
+  }
+
+  bool matchesType(ASTContext &C, QualType argTy) const;
+
+  bool matchesAnyObjCObjectRef() const { return K == ObjCPointerTy; }
+
+  QualType getRepresentativeType(ASTContext &C) const;
+};
+
 class ConversionSpecifier {
 public:
   enum Kind {
@@ -73,11 +101,11 @@
   const char *getStart() const {
     return Position;
   }
-  
+
   llvm::StringRef getCharacters() const {
     return llvm::StringRef(getStart(), getLength());
   }
-	
+
   bool consumesDataArgument() const {
     switch (kind) {
   	  case PercentArg:
@@ -87,7 +115,7 @@
 		return true;
 	}
   }
-  
+
   bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
   bool isIntArg() const { return kind >= dArg && kind <= iArg; }
   bool isUIntArg() const { return kind >= oArg && kind <= XArg; }
@@ -98,7 +126,7 @@
     // single characters, but we be flexible.
     return 1;
   }
-  
+
 private:
   const char *Position;
   Kind kind;
@@ -121,19 +149,19 @@
 public:
   enum HowSpecified { NotSpecified, Constant, Arg };
 
-  OptionalAmount(HowSpecified h, const char *st) 
+  OptionalAmount(HowSpecified h, const char *st)
     : start(st), hs(h), amt(0) {}
 
   OptionalAmount()
     : start(0), hs(NotSpecified), amt(0) {}
-  
-  OptionalAmount(unsigned i, const char *st) 
+
+  OptionalAmount(unsigned i, const char *st)
     : start(st), hs(Constant), amt(i) {}
 
   HowSpecified getHowSpecified() const { return hs; }
   bool hasDataArgument() const { return hs == Arg; }
 
-  unsigned getConstantAmount() const { 
+  unsigned getConstantAmount() const {
     assert(hs == Constant);
     return amt;
   }
@@ -141,33 +169,14 @@
   const char *getStart() const {
     return start;
   }
-  
+
+  ArgTypeResult getArgType(ASTContext &Ctx) const;
+
 private:
   const char *start;
   HowSpecified hs;
   unsigned amt;
 };
-  
-class ArgTypeResult {
-  enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy };
-  const Kind K;
-  QualType T;
-  ArgTypeResult(bool) : K(InvalidTy) {}  
-public:
-  ArgTypeResult() : K(UnknownTy) {}
-  ArgTypeResult(QualType t) : K(SpecificTy), T(t) {}
-  ArgTypeResult(CanQualType t) : K(SpecificTy), T(t) {}
-  
-  static ArgTypeResult Invalid() { return ArgTypeResult(true); }
-  
-  bool isValid() const { return K != InvalidTy; }
-  
-  const QualType *getSpecificType() const { 
-    return K == SpecificTy ? &T : 0;
-  }
-    
-  bool matchesAnyObjCObjectRef() const { return K == ObjCPointerTy; }
-};    
 
 class FormatSpecifier {
   LengthModifier LM;
@@ -184,7 +193,7 @@
   FormatSpecifier() : LM(None),
     IsLeftJustified(0), HasPlusPrefix(0), HasSpacePrefix(0),
     HasAlternativeForm(0), HasLeadingZeroes(0) {}
-  
+
   static FormatSpecifier Parse(const char *beg, const char *end);
 
   // Methods for incrementally constructing the FormatSpecifier.
@@ -209,23 +218,23 @@
   LengthModifier getLengthModifier() const {
     return LM;
   }
-  
+
   const OptionalAmount &getFieldWidth() const {
     return FieldWidth;
   }
-  
+
   void setFieldWidth(const OptionalAmount &Amt) {
     FieldWidth = Amt;
   }
-  
+
   void setPrecision(const OptionalAmount &Amt) {
     Precision = Amt;
   }
-  
+
   const OptionalAmount &getPrecision() const {
     return Precision;
   }
-	
+
   /// \brief Returns the builtin type that a data argument
   /// paired with this format specifier should have.  This method
   /// will return null if the format specifier does not have
@@ -236,7 +245,7 @@
   bool isLeftJustified() const { return (bool) IsLeftJustified; }
   bool hasPlusPrefix() const { return (bool) HasPlusPrefix; }
   bool hasAlternativeForm() const { return (bool) HasAlternativeForm; }
-  bool hasLeadingZeros() const { return (bool) HasLeadingZeroes; }  
+  bool hasLeadingZeros() const { return (bool) HasLeadingZeroes; }
   bool hasSpacePrefix() const { return (bool) HasSpacePrefix; }
 };
 
@@ -244,24 +253,24 @@
 public:
   FormatStringHandler() {}
   virtual ~FormatStringHandler();
-  
+
   virtual void HandleIncompleteFormatSpecifier(const char *startSpecifier,
                                                unsigned specifierLen) {}
 
   virtual void HandleNullChar(const char *nullCharacter) {}
-    
-  virtual void 
+
+  virtual void
     HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS,
                                      const char *startSpecifier,
                                      unsigned specifierLen) {}
-  
+
   virtual bool HandleFormatSpecifier(const analyze_printf::FormatSpecifier &FS,
                                      const char *startSpecifier,
                                      unsigned specifierLen) {
     return true;
   }
 };
-  
+
 bool ParseFormatString(FormatStringHandler &H,
                        const char *beg, const char *end);
 

Modified: cfe/trunk/lib/Analysis/PrintfFormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PrintfFormatString.cpp?rev=96310&r1=96309&r2=96310&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/PrintfFormatString.cpp (original)
+++ cfe/trunk/lib/Analysis/PrintfFormatString.cpp Mon Feb 15 19:46:59 2010
@@ -33,7 +33,7 @@
                         const FormatSpecifier &fs)
     : FS(fs), Start(start), Stop(false) {}
 
-  
+
   const char *getStart() const { return Start; }
   bool shouldStop() const { return Stop; }
   bool hasValue() const { return Start != 0; }
@@ -52,16 +52,20 @@
 public:
   UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
     : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
-  
+
   ~UpdateOnReturn() {
     ValueToUpdate = ValueToCopy;
   }
-};  
+};
+
+//===----------------------------------------------------------------------===//
+// Methods for parsing format strings.
+//===----------------------------------------------------------------------===//
 
 static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
   const char *I = Beg;
   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
-  
+
   bool foundDigits = false;
   unsigned accumulator = 0;
 
@@ -75,24 +79,24 @@
 
     if (foundDigits)
       return OptionalAmount(accumulator, Beg);
-    
+
     if (c == '*') {
       ++I;
       return OptionalAmount(OptionalAmount::Arg, Beg);
     }
-    
+
     break;
   }
-  
-  return OptionalAmount();  
+
+  return OptionalAmount();
 }
 
 static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
                                                   const char *&Beg,
                                                   const char *E) {
-  
+
   using namespace clang::analyze_printf;
-  
+
   const char *I = Beg;
   const char *Start = 0;
   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
@@ -110,19 +114,19 @@
       break;
     }
   }
-  
+
   // No format specifier found?
   if (!Start)
     return false;
-  
+
   if (I == E) {
     // No more characters left?
     H.HandleIncompleteFormatSpecifier(Start, E - Start);
     return true;
   }
-      
+
   FormatSpecifier FS;
-  
+
   // Look for flags (if any).
   bool hasMore = true;
   for ( ; I != E; ++I) {
@@ -136,31 +140,31 @@
     }
     if (!hasMore)
       break;
-  }      
+  }
 
   if (I == E) {
     // No more characters left?
     H.HandleIncompleteFormatSpecifier(Start, E - Start);
     return true;
   }
-  
+
   // Look for the field width (if any).
   FS.setFieldWidth(ParseAmount(I, E));
-      
+
   if (I == E) {
     // No more characters left?
     H.HandleIncompleteFormatSpecifier(Start, E - Start);
     return true;
-  }  
-  
-  // Look for the precision (if any).  
+  }
+
+  // Look for the precision (if any).
   if (*I == '.') {
     ++I;
     if (I == E) {
       H.HandleIncompleteFormatSpecifier(Start, E - Start);
       return true;
     }
-    
+
     FS.setPrecision(ParseAmount(I, E));
 
     if (I == E) {
@@ -177,7 +181,7 @@
       break;
     case 'h':
       ++I;
-      lm = (I != E && *I == 'h') ? ++I, AsChar : AsShort;      
+      lm = (I != E && *I == 'h') ? ++I, AsChar : AsShort;
       break;
     case 'l':
       ++I;
@@ -190,7 +194,7 @@
     case 'q': lm = AsLongLong;   ++I; break;
   }
   FS.setLengthModifier(lm);
-  
+
   if (I == E) {
     // No more characters left?
     H.HandleIncompleteFormatSpecifier(Start, E - Start);
@@ -202,7 +206,7 @@
     H.HandleNullChar(I);
     return true;
   }
-  
+
   // Finally, look for the conversion specifier.
   const char *conversionPosition = I++;
   ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
@@ -228,7 +232,7 @@
     case 's': k = ConversionSpecifier::CStrArg;      break;
     case 'p': k = ConversionSpecifier::VoidPtrArg;   break;
     case 'n': k = ConversionSpecifier::OutIntPtrArg; break;
-    case '%': k = ConversionSpecifier::PercentArg;   break;      
+    case '%': k = ConversionSpecifier::PercentArg;   break;
     // Objective-C.
     case '@': k = ConversionSpecifier::ObjCObjArg; break;
     // Glibc specific.
@@ -260,24 +264,127 @@
     if (!H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(),
                                  I - FSR.getStart()))
       return true;
-  }  
-  assert(I == E && "Format string not exhausted");      
+  }
+  assert(I == E && "Format string not exhausted");
   return false;
 }
 
 FormatStringHandler::~FormatStringHandler() {}
 
 //===----------------------------------------------------------------------===//
+// Methods on ArgTypeResult.
+//===----------------------------------------------------------------------===//
+
+bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
+  assert(isValid());
+
+  if (K == UnknownTy)
+    return true;
+
+  if (K == SpecificTy) {
+    argTy = C.getCanonicalType(argTy).getUnqualifiedType();
+
+    if (T == argTy)
+      return true;
+
+    if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
+      switch (BT->getKind()) {
+        default:
+          break;
+        case BuiltinType::Char_S:
+        case BuiltinType::SChar:
+          return T == C.UnsignedCharTy;
+        case BuiltinType::Char_U:
+        case BuiltinType::UChar:
+          return T == C.SignedCharTy;
+        case BuiltinType::Short:
+          return T == C.UnsignedShortTy;
+        case BuiltinType::UShort:
+          return T == C.ShortTy;
+        case BuiltinType::Int:
+          return T == C.UnsignedIntTy;
+        case BuiltinType::UInt:
+          return T == C.IntTy;
+        case BuiltinType::Long:
+          return T == C.UnsignedLongTy;
+        case BuiltinType::ULong:
+          return T == C.LongTy;
+        case BuiltinType::LongLong:
+          return T == C.UnsignedLongLongTy;
+        case BuiltinType::ULongLong:
+          return T == C.LongLongTy;
+      }
+
+    return false;
+  }
+
+  if (K == CStrTy) {
+    const PointerType *PT = argTy->getAs<PointerType>();
+    if (!PT)
+      return false;
+
+    QualType pointeeTy = PT->getPointeeType();
+
+    if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
+      switch (BT->getKind()) {
+        case BuiltinType::Void:
+        case BuiltinType::Char_U:
+        case BuiltinType::UChar:
+        case BuiltinType::Char_S:
+        case BuiltinType::SChar:
+          return true;
+        default:
+          break;
+      }
+
+    return false;
+  }
+
+  if (K == WCStrTy) {
+    const PointerType *PT = argTy->getAs<PointerType>();
+    if (!PT)
+      return false;
+
+    QualType pointeeTy = PT->getPointeeType();
+    return pointeeTy == C.WCharTy;
+  }
+
+  return false;
+}
+
+QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
+  assert(isValid());
+  if (K == SpecificTy)
+    return T;
+  if (K == CStrTy)
+    return C.getPointerType(C.CharTy);
+  if (K == WCStrTy)
+    return C.getPointerType(C.WCharTy);
+  if (K == ObjCPointerTy)
+    return C.ObjCBuiltinIdTy;
+
+  return QualType();
+}
+
+//===----------------------------------------------------------------------===//
+// Methods on OptionalAmount.
+//===----------------------------------------------------------------------===//
+
+ArgTypeResult OptionalAmount::getArgType(ASTContext &Ctx) const {
+  return Ctx.IntTy;
+}
+
+//===----------------------------------------------------------------------===//
 // Methods on FormatSpecifier.
 //===----------------------------------------------------------------------===//
 
 ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const {
   if (!CS.consumesDataArgument())
     return ArgTypeResult::Invalid();
-  
+
   if (CS.isIntArg())
     switch (LM) {
-      case AsLongDouble: 
+      case AsLongDouble:
         return ArgTypeResult::Invalid();
       case None: return Ctx.IntTy;
       case AsChar: return Ctx.SignedCharTy;
@@ -293,7 +400,7 @@
 
   if (CS.isUIntArg())
     switch (LM) {
-      case AsLongDouble: 
+      case AsLongDouble:
         return ArgTypeResult::Invalid();
       case None: return Ctx.UnsignedIntTy;
       case AsChar: return Ctx.UnsignedCharTy;
@@ -303,7 +410,7 @@
       case AsIntMax:
         // FIXME: Return unknown for now.
         return ArgTypeResult();
-      case AsSizeT: 
+      case AsSizeT:
         // FIXME: How to get the corresponding unsigned
         // version of size_t?
         return ArgTypeResult();
@@ -312,13 +419,17 @@
         // version of ptrdiff_t?
         return ArgTypeResult();
     }
-  
+
   if (CS.isDoubleArg()) {
     if (LM == AsLongDouble)
       return Ctx.LongDoubleTy;
     return Ctx.DoubleTy;
   }
 
+  if (CS.getKind() == ConversionSpecifier::CStrArg)
+    return ArgTypeResult(LM == AsWideChar ? ArgTypeResult::WCStrTy
+                                          : ArgTypeResult::CStrTy);
+
   // FIXME: Handle other cases.
   return ArgTypeResult();
 }

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=96310&r1=96309&r2=96310&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Mon Feb 15 19:46:59 2010
@@ -754,7 +754,7 @@
   if (!TheCall->getArg(0)->isIntegerConstantExpr(Result, Context))
     return Diag(TheCall->getLocStart(), diag::err_expr_not_ice)
       << TheCall->getArg(0)->getSourceRange();
-  
+
   return false;
 }
 
@@ -930,7 +930,7 @@
   for (NonNullAttr::iterator i = NonNull->begin(), e = NonNull->end();
        i != e; ++i) {
     const Expr *ArgExpr = TheCall->getArg(*i);
-    if (ArgExpr->isNullPointerConstant(Context, 
+    if (ArgExpr->isNullPointerConstant(Context,
                                        Expr::NPC_ValueDependentIsNotNull))
       Diag(TheCall->getCallee()->getLocStart(), diag::warn_null_arg)
         << ArgExpr->getSourceRange();
@@ -1049,7 +1049,7 @@
   const bool HasVAListArg;
   const CallExpr *TheCall;
   unsigned FormatIdx;
-public:  
+public:
   CheckPrintfHandler(Sema &s, const StringLiteral *fexpr,
                      const Expr *origFormatExpr,
                      unsigned numDataArgs, bool isObjCLiteral,
@@ -1060,19 +1060,19 @@
       IsObjCLiteral(isObjCLiteral), Beg(beg),
       HasVAListArg(hasVAListArg),
       TheCall(theCall), FormatIdx(formatIdx) {}
-  
+
   void DoneProcessing();
-     
+
   void HandleIncompleteFormatSpecifier(const char *startSpecifier,
                                        unsigned specifierLen);
-  
+
   void
   HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS,
                                    const char *startSpecifier,
                                    unsigned specifierLen);
-  
+
   void HandleNullChar(const char *nullCharacter);
-  
+
   bool HandleFormatSpecifier(const analyze_printf::FormatSpecifier &FS,
                              const char *startSpecifier,
                              unsigned specifierLen);
@@ -1081,16 +1081,14 @@
   SourceRange getFormatSpecifierRange(const char *startSpecifier,
                                       unsigned specifierLen);
   SourceLocation getLocationOfByte(const char *x);
-  
+
   bool HandleAmount(const analyze_printf::OptionalAmount &Amt,
                     unsigned MissingArgDiag, unsigned BadTypeDiag,
           const char *startSpecifier, unsigned specifierLen);
   void HandleFlags(const analyze_printf::FormatSpecifier &FS,
                    llvm::StringRef flag, llvm::StringRef cspec,
                    const char *startSpecifier, unsigned specifierLen);
-  
-  bool MatchType(QualType A, QualType B, bool ignoreSign);
-  
+
   const Expr *getDataArg(unsigned i) const;
 };
 }
@@ -1106,12 +1104,12 @@
 }
 
 SourceLocation CheckPrintfHandler::getLocationOfByte(const char *x) {
-  return S.getLocationOfStringLiteralByte(FExpr, x - Beg);  
+  return S.getLocationOfStringLiteralByte(FExpr, x - Beg);
 }
 
 void CheckPrintfHandler::
 HandleIncompleteFormatSpecifier(const char *startSpecifier,
-                                unsigned specifierLen) {  
+                                unsigned specifierLen) {
   SourceLocation Loc = getLocationOfByte(startSpecifier);
   S.Diag(Loc, diag::warn_printf_incomplete_specifier)
     << getFormatSpecifierRange(startSpecifier, specifierLen);
@@ -1121,14 +1119,14 @@
 HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS,
                                  const char *startSpecifier,
                                  unsigned specifierLen) {
-  
+
   ++NumConversions;
   const analyze_printf::ConversionSpecifier &CS =
-    FS.getConversionSpecifier();  
+    FS.getConversionSpecifier();
   SourceLocation Loc = getLocationOfByte(CS.getStart());
   S.Diag(Loc, diag::warn_printf_invalid_conversion)
       << llvm::StringRef(CS.getStart(), CS.getLength())
-      << getFormatSpecifierRange(startSpecifier, specifierLen);  
+      << getFormatSpecifierRange(startSpecifier, specifierLen);
 }
 
 void CheckPrintfHandler::HandleNullChar(const char *nullCharacter) {
@@ -1139,49 +1137,10 @@
 }
 
 const Expr *CheckPrintfHandler::getDataArg(unsigned i) const {
-  return TheCall->getArg(FormatIdx + i);  
+  return TheCall->getArg(FormatIdx + i);
 }
 
-bool CheckPrintfHandler::MatchType(QualType A, QualType B, bool ignoreSign) {
-  A = S.Context.getCanonicalType(A).getUnqualifiedType();
-  B = S.Context.getCanonicalType(B).getUnqualifiedType();
-  
-  if (A == B)
-    return true;
-  
-  if (ignoreSign) {
-    if (const BuiltinType *BT = B->getAs<BuiltinType>()) {
-      switch (BT->getKind()) {
-        default:
-          return false;
-        case BuiltinType::Char_S:          
-        case BuiltinType::SChar:
-          return A == S.Context.UnsignedCharTy;
-        case BuiltinType::Char_U:
-        case BuiltinType::UChar:
-          return A == S.Context.SignedCharTy;
-        case BuiltinType::Short:
-          return A == S.Context.UnsignedShortTy;
-        case BuiltinType::UShort:
-          return A == S.Context.ShortTy;          
-        case BuiltinType::Int:
-          return A == S.Context.UnsignedIntTy;
-        case BuiltinType::UInt:
-          return A == S.Context.IntTy;
-        case BuiltinType::Long:
-          return A == S.Context.UnsignedLongTy;
-        case BuiltinType::ULong:
-          return A == S.Context.LongTy;
-        case BuiltinType::LongLong:
-          return A == S.Context.UnsignedLongLongTy;
-        case BuiltinType::ULongLong:
-          return A == S.Context.LongLongTy;          
-      }
-      return A == B;
-    }
-  }
-  return false;  
-}
+
 
 void CheckPrintfHandler::HandleFlags(const analyze_printf::FormatSpecifier &FS,
                                      llvm::StringRef flag,
@@ -1205,21 +1164,25 @@
     if (!HasVAListArg) {
       if (NumConversions > NumDataArgs) {
         S.Diag(getLocationOfByte(Amt.getStart()), MissingArgDiag)
-          << getFormatSpecifierRange(startSpecifier, specifierLen);      
+          << getFormatSpecifierRange(startSpecifier, specifierLen);
         // Don't do any more checking.  We will just emit
         // spurious errors.
         return false;
       }
-      
+
       // Type check the data argument.  It should be an 'int'.
       // Although not in conformance with C99, we also allow the argument to be
       // an 'unsigned int' as that is a reasonably safe case.  GCC also
       // doesn't emit a warning for that case.
       const Expr *Arg = getDataArg(NumConversions);
       QualType T = Arg->getType();
-      if (!MatchType(T, S.Context.IntTy, true)) {
+
+      const analyze_printf::ArgTypeResult &ATR = Amt.getArgType(S.Context);
+      assert(ATR.isValid());
+
+      if (!ATR.matchesType(S.Context, T)) {
         S.Diag(getLocationOfByte(Amt.getStart()), BadTypeDiag)
-          << S.Context.IntTy << T
+          << ATR.getRepresentativeType(S.Context) << T
           << getFormatSpecifierRange(startSpecifier, specifierLen)
           << Arg->getSourceRange();
         // Don't do any more checking.  We will just emit
@@ -1248,7 +1211,7 @@
           startSpecifier, specifierLen)) {
     return false;
   }
-    
+
   if (!HandleAmount(FS.getPrecision(),
                     diag::warn_printf_asterisk_precision_missing_arg,
                     diag::warn_printf_asterisk_precision_wrong_type,
@@ -1260,7 +1223,7 @@
   // in a non-ObjC literal.
   if (!IsObjCLiteral && CS.isObjCArg()) {
     HandleInvalidConversionSpecifier(FS, startSpecifier, specifierLen);
-    
+
     // Continue checking the other format specifiers.
     return true;
   }
@@ -1270,27 +1233,27 @@
     // makes no sense.  Worth issuing a warning at some point.
     return true;
   }
-  
-  ++NumConversions;  
-  
+
+  ++NumConversions;
+
   // Are we using '%n'?  Issue a warning about this being
   // a possible security issue.
   if (CS.getKind() == ConversionSpecifier::OutIntPtrArg) {
     S.Diag(getLocationOfByte(CS.getStart()), diag::warn_printf_write_back)
-      << getFormatSpecifierRange(startSpecifier, specifierLen);           
+      << getFormatSpecifierRange(startSpecifier, specifierLen);
     // Continue checking the other format specifiers.
     return true;
   }
 
   if (CS.getKind() == ConversionSpecifier::VoidPtrArg) {
     if (FS.getPrecision().getHowSpecified() != OptionalAmount::NotSpecified)
-      S.Diag(getLocationOfByte(CS.getStart()), 
+      S.Diag(getLocationOfByte(CS.getStart()),
              diag::warn_printf_nonsensical_precision)
         << CS.getCharacters()
         << getFormatSpecifierRange(startSpecifier, specifierLen);
   }
-  if (CS.getKind() == ConversionSpecifier::VoidPtrArg || 
-      CS.getKind() == ConversionSpecifier::CStrArg) {    
+  if (CS.getKind() == ConversionSpecifier::VoidPtrArg ||
+      CS.getKind() == ConversionSpecifier::CStrArg) {
     // FIXME: Instead of using "0", "+", etc., eventually get them from
     // the FormatSpecifier.
     if (FS.hasLeadingZeros())
@@ -1299,42 +1262,38 @@
       HandleFlags(FS, "+", CS.getCharacters(), startSpecifier, specifierLen);
     if (FS.hasSpacePrefix())
       HandleFlags(FS, " ", CS.getCharacters(), startSpecifier, specifierLen);
-  }  
-  
+  }
+
   // The remaining checks depend on the data arguments.
   if (HasVAListArg)
     return true;
-  
+
   if (NumConversions > NumDataArgs) {
     S.Diag(getLocationOfByte(CS.getStart()),
            diag::warn_printf_insufficient_data_args)
-      << getFormatSpecifierRange(startSpecifier, specifierLen);    
+      << getFormatSpecifierRange(startSpecifier, specifierLen);
     // Don't do any more checking.
     return false;
   }
-  
+
   // Now type check the data expression that matches the
   // format specifier.
   const Expr *Ex = getDataArg(NumConversions);
   const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context);
-  
-  if (const QualType *T = ATR.getSpecificType()) {
-    if (!MatchType(*T, Ex->getType(), true)) {
-      // Check if we didn't match because of an implicit cast from a 'char'
-      // or 'short' to an 'int'.  This is done because printf is a varargs
-      // function.
-      if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Ex))
-        if (ICE->getType() == S.Context.IntTy)
-          if (MatchType(*T, ICE->getSubExpr()->getType(), true))
-            return true;
+  if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) {
+    // Check if we didn't match because of an implicit cast from a 'char'
+    // or 'short' to an 'int'.  This is done because printf is a varargs
+    // function.
+    if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Ex))
+      if (ICE->getType() == S.Context.IntTy)
+        if (ATR.matchesType(S.Context, ICE->getSubExpr()->getType()))
+          return true;
 
-      S.Diag(getLocationOfByte(CS.getStart()),
-             diag::warn_printf_conversion_argument_type_mismatch)
-      << *T << Ex->getType()
+    S.Diag(getLocationOfByte(CS.getStart()),
+           diag::warn_printf_conversion_argument_type_mismatch)
+      << ATR.getRepresentativeType(S.Context) << Ex->getType()
       << getFormatSpecifierRange(startSpecifier, specifierLen)
       << Ex->getSourceRange();
-    }
-    return true;
   }
 
   return true;
@@ -1361,19 +1320,19 @@
     << OrigFormatExpr->getSourceRange();
     return;
   }
-  
+
   // Str - The format string.  NOTE: this is NOT null-terminated!
   const char *Str = FExpr->getStrData();
-  
+
   // CHECK: empty format string?
   unsigned StrLen = FExpr->getByteLength();
-  
+
   if (StrLen == 0) {
     Diag(FExpr->getLocStart(), diag::warn_printf_empty_format_string)
     << OrigFormatExpr->getSourceRange();
     return;
   }
-  
+
   CheckPrintfHandler H(*this, FExpr, OrigFormatExpr,
                        TheCall->getNumArgs() - firstDataArg,
                        isa<ObjCStringLiteral>(OrigFormatExpr), Str,
@@ -1407,11 +1366,11 @@
       if (C->hasBlockDeclRefExprs())
         Diag(C->getLocStart(), diag::err_ret_local_block)
           << C->getSourceRange();
-    
+
     if (AddrLabelExpr *ALE = dyn_cast<AddrLabelExpr>(RetValExp))
       Diag(ALE->getLocStart(), diag::warn_ret_addr_label)
         << ALE->getSourceRange();
-    
+
   } else if (lhsType->isReferenceType()) {
     // Perform checking for stack values returned by reference.
     // Check for a reference to the stack
@@ -1887,7 +1846,7 @@
       if (BO->getLHS()->getType()->isPointerType())
         return IntRange::forType(C, E->getType());
       // fallthrough
-      
+
     default:
       break;
     }
@@ -2328,7 +2287,7 @@
   CFG *cfg = AC.getCFG();
   if (cfg == 0)
     return;
-  
+
   llvm::BitVector live(cfg->getNumBlockIDs());
   // Mark all live things first.
   count = MarkLive(&cfg->getEntry(), live);
@@ -2527,7 +2486,7 @@
   // which this code would then warn about.
   if (getDiagnostics().hasErrorOccurred())
     return;
-  
+
   bool ReturnsVoid = false;
   bool HasNoReturn = false;
   if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {

Modified: cfe/trunk/test/Sema/block-printf-attribute-1.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/block-printf-attribute-1.c?rev=96310&r1=96309&r2=96310&view=diff

==============================================================================
--- cfe/trunk/test/Sema/block-printf-attribute-1.c (original)
+++ cfe/trunk/test/Sema/block-printf-attribute-1.c Mon Feb 15 19:46:59 2010
@@ -6,7 +6,6 @@
  
   void (^z) (int arg, const char * format, ...) __attribute__ ((__format__ (__printf__, 2, 3))) = ^ __attribute__ ((__format__ (__printf__, 2, 3))) (int arg, const char * format, ...) {};
 
-  // FIXME: argument type poking not yet supportted.
-  z(1, "%s", 1); /* { dg-warning "format \\'\%s\\' expects type \\'char \\*\\'\, but argument 3 has type \\'int\\'" } */
-  z(1, "%s", "HELLO"); // OK
+  z(1, "%s", 1); // expected-warning{{conversion specifies type 'char *' but the argument has type 'int'}}
+  z(1, "%s", "HELLO"); // no-warning
 }

Modified: cfe/trunk/test/Sema/format-strings.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings.c?rev=96310&r1=96309&r2=96310&view=diff

==============================================================================
--- cfe/trunk/test/Sema/format-strings.c (original)
+++ cfe/trunk/test/Sema/format-strings.c Mon Feb 15 19:46:59 2010
@@ -183,6 +183,12 @@
   printf("%0s", p); // expected-warning{{flag '0' results in undefined behavior in 's' conversion specifier}}
 }
 
+void test12() {
+  unsigned char buf[4];
+  printf ("%.4s\n", buf); // no-warning
+  printf ("%.4s\n", &buf); // expected-result{{conversion specifies type 'char *' but the argument has type 'unsigned char (*)[4]'}}
+}
+
 typedef struct __aslclient *aslclient;
 typedef struct __aslmsg *aslmsg;
 int asl_log(aslclient asl, aslmsg msg, int level, const char *format, ...) __attribute__((__format__ (__printf__, 4, 5)));





More information about the cfe-commits mailing list