]> granicus.if.org Git - clang/commitdiff
Objective-C. Under a special flag, -Wcstring-format-directive,
authorFariborz Jahanian <fjahanian@apple.com>
Thu, 11 Sep 2014 19:13:23 +0000 (19:13 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Thu, 11 Sep 2014 19:13:23 +0000 (19:13 +0000)
off by default, issue a warning if %s directive is used
in formart argument of a function/method declared as
__attribute__((format(CF/NSString, ...)))
To complete rdar://18182443

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@217619 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/Sema.h
lib/Sema/SemaChecking.cpp
lib/Sema/SemaExprObjC.cpp
test/SemaObjC/format-cstrings-warning.m

index d0a49596d118d1715ab19caa7ed07502724d7a10..dedc4721d5c80f60c6fbb519ce7620d6e3a6f745 100644 (file)
@@ -8405,6 +8405,8 @@ public:
                          llvm::SmallBitVector &CheckedVarArgs);
   
   bool FormatStringHasSArg(const StringLiteral *FExpr);
+  
+  bool GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx);
 
 private:
   bool CheckFormatArguments(const FormatAttr *Format,
index 0c3a3df1f185a96ecefee2d2431fd682c7a24c13..ac5b68fb2331afef832d6eb73b53c2ab7332be3e 100644 (file)
@@ -767,6 +767,15 @@ static void CheckNonNullArgument(Sema &S,
     S.Diag(CallSiteLoc, diag::warn_null_arg) << ArgExpr->getSourceRange();
 }
 
+bool Sema::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) {
+  FormatStringInfo FSI;
+  if ((GetFormatStringType(Format) == FST_NSString) &&
+      getFormatStringInfo(Format, false, &FSI)) {
+    Idx = FSI.FormatIdx;
+    return true;
+  }
+  return false;
+}
 /// \brief Diagnose use of %s directive in an NSString which is being passed
 /// as formatting string to formatting method.
 static void
@@ -774,27 +783,38 @@ DiagnoseCStringFormatDirectiveInCFAPI(Sema &S,
                                         const NamedDecl *FDecl,
                                         Expr **Args,
                                         unsigned NumArgs) {
-  if (NumArgs < 3)
-    return;
+  unsigned Idx = 0;
+  bool Format = false;
   ObjCStringFormatFamily SFFamily = FDecl->getObjCFStringFormattingFamily();
   if (SFFamily == ObjCStringFormatFamily::SFF_CFString) {
-    const Expr *FormatExpr = Args[2];
-    if (const CStyleCastExpr *CSCE = dyn_cast<CStyleCastExpr>(FormatExpr))
-      FormatExpr = CSCE->getSubExpr();
-    const StringLiteral *FormatString;
-    if (const ObjCStringLiteral *OSL =
-        dyn_cast<ObjCStringLiteral>(FormatExpr->IgnoreParenImpCasts()))
-      FormatString = OSL->getString();
-    else
-      FormatString = dyn_cast<StringLiteral>(FormatExpr->IgnoreParenImpCasts());
-    if (!FormatString)
-      return;
-    if (S.FormatStringHasSArg(FormatString)) {
-      S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string)
-        << "%s" << 1 << 1;
-        S.Diag(FDecl->getLocation(), diag::note_entity_declared_at)
-          << FDecl->getDeclName();
+    Idx = 2;
+    Format = true;
+  }
+  else
+    for (const auto *I : FDecl->specific_attrs<FormatAttr>()) {
+      if (S.GetFormatNSStringIdx(I, Idx)) {
+        Format = true;
+        break;
+      }
     }
+  if (!Format || NumArgs <= Idx)
+    return;
+  const Expr *FormatExpr = Args[Idx];
+  if (const CStyleCastExpr *CSCE = dyn_cast<CStyleCastExpr>(FormatExpr))
+    FormatExpr = CSCE->getSubExpr();
+  const StringLiteral *FormatString;
+  if (const ObjCStringLiteral *OSL =
+      dyn_cast<ObjCStringLiteral>(FormatExpr->IgnoreParenImpCasts()))
+    FormatString = OSL->getString();
+  else
+    FormatString = dyn_cast<StringLiteral>(FormatExpr->IgnoreParenImpCasts());
+  if (!FormatString)
+    return;
+  if (S.FormatStringHasSArg(FormatString)) {
+    S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string)
+      << "%s" << 1 << 1;
+    S.Diag(FDecl->getLocation(), diag::note_entity_declared_at)
+      << FDecl->getDeclName();
   }
 }
 
@@ -930,8 +950,8 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
     return false;
 
   CheckAbsoluteValueFunction(TheCall, FDecl, FnInfo);
-  
-  DiagnoseCStringFormatDirectiveInCFAPI(*this, FDecl, Args, NumArgs);
+  if (getLangOpts().ObjC1)
+    DiagnoseCStringFormatDirectiveInCFAPI(*this, FDecl, Args, NumArgs);
 
   unsigned CMId = FDecl->getMemoryFunctionKind();
   if (CMId == 0)
index d1c7aa6a435b33058aa0bc1fb7f7072cdbaf2e09..ac28d833823b147dda7a4fd7ac89caddb0743ae3 100644 (file)
@@ -2121,21 +2121,34 @@ DiagnoseCStringFormatDirectiveInObjCAPI(Sema &S,
                                         ObjCMethodDecl *Method,
                                         Selector Sel,
                                         Expr **Args, unsigned NumArgs) {
-  if (NumArgs == 0)
-    return;
+  unsigned Idx = 0;
+  bool Format = false;
   ObjCStringFormatFamily SFFamily = Sel.getStringFormatFamily();
   if (SFFamily == ObjCStringFormatFamily::SFF_NSString) {
-    Expr *FormatExpr = Args[0];
-    if (ObjCStringLiteral *OSL =
-        dyn_cast<ObjCStringLiteral>(FormatExpr->IgnoreParenImpCasts())) {
-      StringLiteral *FormatString = OSL->getString();
-      if (S.FormatStringHasSArg(FormatString)) {
-        S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string)
+    Idx = 0;
+    Format = true;
+  }
+  else if (Method) {
+    for (const auto *I : Method->specific_attrs<FormatAttr>()) {
+      if (S.GetFormatNSStringIdx(I, Idx)) {
+        Format = true;
+        break;
+      }
+    }
+  }
+  if (!Format || NumArgs <= Idx)
+    return;
+  
+  Expr *FormatExpr = Args[Idx];
+  if (ObjCStringLiteral *OSL =
+      dyn_cast<ObjCStringLiteral>(FormatExpr->IgnoreParenImpCasts())) {
+    StringLiteral *FormatString = OSL->getString();
+    if (S.FormatStringHasSArg(FormatString)) {
+      S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string)
         << "%s" << 0 << 0;
-        if (Method)
-          S.Diag(Method->getLocation(), diag::note_method_declared_at)
+      if (Method)
+        S.Diag(Method->getLocation(), diag::note_method_declared_at)
           << Method->getDeclName();
-      }
     }
   }
 }
index dea9cbd4768596746d472ae02a39f73d23bc0f45..28fa7ce0dcd8c3a8589b8cfc5c4a8ee7e1aac864 100644 (file)
@@ -4,16 +4,20 @@
 typedef __builtin_va_list __darwin_va_list;
 typedef __builtin_va_list va_list;
 
-@interface NSString @end
+@interface NSString 
+@end
+
+va_list argList;
 
 @interface NSString (NSStringExtensionMethods)
 - (NSString *)stringByAppendingFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2)));
-- (instancetype)initWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2))); // expected-note {{method 'initWithFormat:' declared here}}
+- (instancetype)initWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2))); // expected-note {{method 'initWithFormat:' declared here}}
 - (instancetype)initWithFormat:(NSString *)format arguments:(va_list)argList __attribute__((format(__NSString__, 1, 0)));
 - (instancetype)initWithFormat:(NSString *)format locale:(id)locale, ... __attribute__((format(__NSString__, 1, 3)));
 - (instancetype)initWithFormat:(NSString *)format locale:(id)locale arguments:(va_list)argList __attribute__((format(__NSString__, 1, 0)));
 + (instancetype)stringWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2))); // expected-note {{method 'stringWithFormat:' declared here}}
-+ (instancetype)localizedStringWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2)));
++ (instancetype)localizedStringWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2))); // expected-note {{method 'localizedStringWithFormat:' declared here}}
+- (void)MyRandomMethod:(NSString *)format locale:(id)locale arguments:(va_list)argList __attribute__((format(__NSString__, 1, 0))); // expected-note {{method 'MyRandomMethod:locale:arguments:' declared here}}
 @end
 
 @interface NSMutableString : NSString
@@ -27,6 +31,9 @@ typedef __builtin_va_list va_list;
 
 NSString *ns(NSString *pns) {
   [pns initWithFormat: @"Number %d length %c name %s", 1, 'a', "something"]; // expected-warning {{using %s directive in NSString which is being passed as a formatting argument to the formatting method}}
+  [NSString localizedStringWithFormat : @"Hello%s", " There"]; // expected-warning {{using %s directive in NSString which is being passed as a formatting argument to the formatting method}}
+  [pns initWithFormat : @"Hello%s %d %d", "Hello", 1, 2]; // expected-warning {{using %s directive in NSString which is being passed as a formatting argument to the formatting method}}
+  [pns MyRandomMethod : @"Hello%s %d %d" locale:0 arguments: argList];  // expected-warning {{using %s directive in NSString which is being passed as a formatting argument to the formatting method}}
   return [NSString stringWithFormat : @"Hello%s", " There"]; // expected-warning {{using %s directive in NSString which is being passed as a formatting argument to the formatting method}}
 }
 
@@ -51,10 +58,22 @@ void CFStringAppendFormat(CFMutableStringRef theString, CFDictionaryRef formatOp
 extern
 void CFStringAppendFormatAndArguments(CFMutableStringRef theString, CFDictionaryRef formatOptions, CFStringRef format, va_list arguments) __attribute__((format(CFString, 3, 0))); // expected-note {{'CFStringAppendFormatAndArguments' declared here}}
 
-void foo(va_list argList) {
+void Test1(va_list argList) {
   CFAllocatorRef alloc;
   CFStringCreateWithFormatAndArguments (alloc, 0, (CFStringRef)@"%s\n", argList); // expected-warning {{using %s directive in CFString which is being passed as a formatting argument to the formatting CFfunction}}
   CFStringAppendFormatAndArguments ((CFMutableStringRef)@"AAAA", 0, (CFStringRef)"Hello %s there %d\n", argList); // expected-warning {{using %s directive in CFString which is being passed as a formatting argument to the formatting CFfunction}}
   CFStringCreateWithFormatAndArguments (alloc, 0, (CFStringRef)@"%c\n", argList);
   CFStringAppendFormatAndArguments ((CFMutableStringRef)@"AAAA", 0, (CFStringRef)"%d\n", argList);
 }
+
+extern void MyNSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); // expected-note {{'MyNSLog' declared here}}
+extern void MyCFStringCreateWithFormat(CFStringRef format, ...) __attribute__((format(__CFString__, 1, 2))); // expected-note {{'MyCFStringCreateWithFormat' declared here}}
+extern void XMyNSLog(int, NSString *format, ...) __attribute__((format(__NSString__, 2, 3))); // expected-note {{'XMyNSLog' declared here}}
+
+void Test2() {
+  MyNSLog(@"%s\n", "Hello"); // expected-warning {{using %s directive in CFString which is being passed as a formatting argument to the formatting CFfunction}}
+
+  MyCFStringCreateWithFormat((CFStringRef)@"%s", "Hello"); // expected-warning {{using %s directive in CFString which is being passed as a formatting argument to the formatting CFfunction}}
+  XMyNSLog(4, @"%s\n", "Hello"); // expected-warning {{using %s directive in CFString which is being passed as a formatting argument to the formatting CFfunction}}
+}
+