]> granicus.if.org Git - clang/commitdiff
Patch by Roman Divacky:
authorTed Kremenek <kremenek@apple.com>
Mon, 12 Jan 2009 23:09:09 +0000 (23:09 +0000)
committerTed Kremenek <kremenek@apple.com>
Mon, 12 Jan 2009 23:09:09 +0000 (23:09 +0000)
Extend string-literal checking for printf() format string to handle conditional
ternary operators where both sides are literals.

This fixes PR 3319: http://llvm.org/bugs/show_bug.cgi?id=3319

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

lib/Sema/Sema.h
lib/Sema/SemaChecking.cpp
test/Sema/format-strings.c

index f098372d97f4cc666dab1f72d856f6bbae54c20f..fc619c6f1f2274a6ce364111d1383279ffa48d2a 100644 (file)
@@ -1516,6 +1516,11 @@ private:
   Action::ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall);
   bool SemaBuiltinPrefetch(CallExpr *TheCall); 
   bool SemaBuiltinObjectSize(CallExpr *TheCall); 
+  bool SemaCheckStringLiteral(Expr *E, CallExpr *TheCall, bool HasVAListArg,
+                              unsigned format_idx);
+  void CheckPrintfString(StringLiteral *FExpr, Expr *OrigFormatExpr,
+                         CallExpr *TheCall, bool HasVAListArg,
+                         unsigned format_idx);
   void CheckPrintfArguments(CallExpr *TheCall,
                             bool HasVAListArg, unsigned format_idx);
   void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
index 5bb78cd765d8ad1074834040e2a81fd7cdbf8e04..ff9d75302f7821917055eb31484468ca6988363f 100644 (file)
@@ -369,6 +369,51 @@ bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
   return false;
 }
 
+// Handle i > 1 ? "x" : "y", recursivelly
+bool Sema::SemaCheckStringLiteral(Expr *E, CallExpr *TheCall, bool HasVAListArg,
+                                  unsigned format_idx) {
+
+  switch (E->getStmtClass()) {
+  case Stmt::ConditionalOperatorClass: {
+    ConditionalOperator *C = cast<ConditionalOperator>(E);
+    return SemaCheckStringLiteral(C->getLHS(), TheCall,
+                                  HasVAListArg, format_idx)
+        && SemaCheckStringLiteral(C->getRHS(), TheCall,
+                                  HasVAListArg, format_idx);
+  }
+
+  case Stmt::ImplicitCastExprClass: {
+    ImplicitCastExpr *Expr = dyn_cast<ImplicitCastExpr>(E);
+    return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg,
+                                  format_idx);
+  }
+
+  case Stmt::ParenExprClass: {
+    ParenExpr *Expr = dyn_cast<ParenExpr>(E);
+    return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg,
+                                  format_idx);
+  }
+
+  default: {
+    ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(E);
+    StringLiteral *StrE = NULL;
+
+    if (ObjCFExpr)
+      StrE = ObjCFExpr->getString();
+    else
+      StrE = dyn_cast<StringLiteral>(E);
+
+    if (StrE) {
+      CheckPrintfString(StrE, E, TheCall, HasVAListArg, format_idx);
+      return true;
+    }
+    
+    return false;
+  }
+  }
+}
+
+
 /// CheckPrintfArguments - Check calls to printf (and similar functions) for
 /// correct use of format strings.  
 ///
@@ -444,15 +489,9 @@ Sema::CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg,
   // C string (e.g. "%d")
   // ObjC string uses the same format specifiers as C string, so we can use 
   // the same format string checking logic for both ObjC and C strings.
-  ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(OrigFormatExpr);
-  StringLiteral *FExpr = NULL;
-
-  if(ObjCFExpr != NULL) 
-    FExpr = ObjCFExpr->getString();
-  else
-    FExpr = dyn_cast<StringLiteral>(OrigFormatExpr);
+  bool isFExpr = SemaCheckStringLiteral(OrigFormatExpr, TheCall, HasVAListArg, format_idx);
 
-  if (FExpr == NULL) {
+  if (!isFExpr) {
     // For vprintf* functions (i.e., HasVAListArg==true), we add a
     // special check to see if the format string is a function parameter
     // of the function calling the printf function.  If the function
@@ -475,13 +514,18 @@ Sema::CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg,
       if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(OrigFormatExpr))
         if (isa<ParmVarDecl>(DR->getDecl()))
           return;
-    
+
     Diag(TheCall->getArg(format_idx)->getLocStart(), 
          diag::warn_printf_not_string_constant)
       << OrigFormatExpr->getSourceRange();
     return;
   }
+}
+
+void Sema::CheckPrintfString(StringLiteral *FExpr, Expr *OrigFormatExpr,
+      CallExpr *TheCall, bool HasVAListArg, unsigned format_idx) {
 
+  ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(OrigFormatExpr);
   // CHECK: is the format string a wide literal?
   if (FExpr->isWide()) {
     Diag(FExpr->getLocStart(),
index 16d4943cda5f479f08a1299e576eaf5a35bd3d27..19c29db343d5e1f335ccccab58648439763c0b50 100644 (file)
@@ -31,6 +31,12 @@ void check_string_literal( FILE* fp, const char* s, char *buf, ... ) {
   __builtin___vsnprintf_chk(buf,2,0,-1,global_fmt,ap); // expected-warning {{format string is not a string literal}}
 }
 
+void check_conditional_literal(const char* s, int i) {
+  printf(i == 1 ? "yes" : "no"); // no-warning
+  printf(i == 0 ? (i == 1 ? "yes" : "no") : "dont know"); // no-warning
+  printf(i == 0 ? (i == 1 ? s : "no") : "dont know"); // expected-warning
+}
+
 void check_writeback_specifier()
 {
   int x;