[cfe-commits] r151080 - in /cfe/trunk: lib/Sema/SemaChecking.cpp test/Sema/format-strings.c test/SemaCXX/format-strings.cpp test/SemaObjC/format-strings-objc.m

Jean-Daniel Dupas devlists at shadowlab.org
Tue Feb 21 12:00:53 PST 2012


Author: jddupas
Date: Tue Feb 21 14:00:53 2012
New Revision: 151080

URL: http://llvm.org/viewvc/llvm-project?rev=151080&view=rev
Log:
When calling a non variadic format function(vprintf, vscanf, NSLogv, …), warn if the format string argument is a parameter that is not itself declared as a format string with compatible format.


Modified:
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/test/Sema/format-strings.c
    cfe/trunk/test/SemaCXX/format-strings.cpp
    cfe/trunk/test/SemaObjC/format-strings-objc.m

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=151080&r1=151079&r2=151080&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Tue Feb 21 14:00:53 2012
@@ -1447,13 +1447,27 @@
       //      vprintf(fmt, ap);  // Do NOT emit a warning about "fmt".
       //      ...
       //
-      //
-      //  FIXME: We don't have full attribute support yet, so just check to see
-      //    if the argument is a DeclRefExpr that references a parameter.  We'll
-      //    add proper support for checking the attribute later.
-      if (HasVAListArg)
-        if (isa<ParmVarDecl>(VD))
-          return true;
+      if (HasVAListArg) {
+        if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(VD)) {
+          if (const NamedDecl *ND = dyn_cast<NamedDecl>(PV->getDeclContext())) {
+            int PVIndex = PV->getFunctionScopeIndex() + 1;
+            for (specific_attr_iterator<FormatAttr>
+                 i = ND->specific_attr_begin<FormatAttr>(),
+                 e = ND->specific_attr_end<FormatAttr>(); i != e ; ++i) {
+              FormatAttr *PVFormat = *i;
+              // adjust for implicit parameter
+              if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND))
+                if (MD->isInstance())
+                  ++PVIndex;
+              // We also check if the formats are compatible.
+              // We can't pass a 'scanf' string to a 'printf' function.
+              if (PVIndex == PVFormat->getFormatIdx() &&
+                  Type == GetFormatStringType(PVFormat))
+                return true;
+            }
+          }
+        }
+      }
     }
 
     return false;

Modified: cfe/trunk/test/Sema/format-strings.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings.c?rev=151080&r1=151079&r2=151080&view=diff
==============================================================================
--- cfe/trunk/test/Sema/format-strings.c (original)
+++ cfe/trunk/test/Sema/format-strings.c Tue Feb 21 14:00:53 2012
@@ -14,6 +14,8 @@
 int vsnprintf(char *, size_t, const char *, va_list);
 int vsprintf(char *restrict, const char *restrict, va_list); // expected-note{{passing argument to parameter here}}
 
+int vscanf(const char *restrict format, va_list arg);
+
 char * global_fmt;
 
 void check_string_literal( FILE* fp, const char* s, char *buf, ... ) {
@@ -23,21 +25,23 @@
   va_start(ap,buf);
 
   printf(s); // expected-warning {{format string is not a string literal}}
-  vprintf(s,ap); // // no-warning
+  vprintf(s,ap); // expected-warning {{format string is not a string literal}}
   fprintf(fp,s); // expected-warning {{format string is not a string literal}}
-  vfprintf(fp,s,ap); // no-warning
+  vfprintf(fp,s,ap); // expected-warning {{format string is not a string literal}}
   asprintf(&b,s); // expected-warning {{format string is not a string lit}}
-  vasprintf(&b,s,ap); // no-warning
+  vasprintf(&b,s,ap); // expected-warning {{format string is not a string literal}}
   sprintf(buf,s); // expected-warning {{format string is not a string literal}}
   snprintf(buf,2,s); // expected-warning {{format string is not a string lit}}
   __builtin___sprintf_chk(buf,0,-1,s); // expected-warning {{format string is not a string literal}}
   __builtin___snprintf_chk(buf,2,0,-1,s); // expected-warning {{format string is not a string lit}}
-  vsprintf(buf,s,ap); // no-warning
-  vsnprintf(buf,2,s,ap); // no-warning
+  vsprintf(buf,s,ap); // expected-warning {{format string is not a string lit}}
+  vsnprintf(buf,2,s,ap); // expected-warning {{format string is not a string lit}}
   vsnprintf(buf,2,global_fmt,ap); // expected-warning {{format string is not a string literal}}
-  __builtin___vsnprintf_chk(buf,2,0,-1,s,ap); // no-warning
+  __builtin___vsnprintf_chk(buf,2,0,-1,s,ap); // expected-warning {{format string is not a string lit}}
   __builtin___vsnprintf_chk(buf,2,0,-1,global_fmt,ap); // expected-warning {{format string is not a string literal}}
 
+  vscanf(s, ap); // expected-warning {{format string is not a string literal}}
+
   // rdar://6079877
   printf("abc"
          "%*d", 1, 1); // no-warning
@@ -51,6 +55,25 @@
   printf("%*d", (unsigned) 1, 1); // no-warning  
 }
 
+__attribute__((__format__ (__printf__, 2, 4)))
+void check_string_literal2( FILE* fp, const char* s, char *buf, ... ) {
+  char * b;
+  va_list ap;
+  va_start(ap,buf);
+
+  printf(s); // expected-warning {{format string is not a string literal}}
+  vprintf(s,ap); // no-warning
+  fprintf(fp,s); // expected-warning {{format string is not a string literal}}
+  vfprintf(fp,s,ap); // no-warning
+  asprintf(&b,s); // expected-warning {{format string is not a string lit}}
+  vasprintf(&b,s,ap); // no-warning
+  sprintf(buf,s); // expected-warning {{format string is not a string literal}}
+  snprintf(buf,2,s); // expected-warning {{format string is not a string lit}}
+  __builtin___vsnprintf_chk(buf,2,0,-1,s,ap); // no-warning
+
+  vscanf(s, 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

Modified: cfe/trunk/test/SemaCXX/format-strings.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/format-strings.cpp?rev=151080&r1=151079&r2=151080&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/format-strings.cpp (original)
+++ cfe/trunk/test/SemaCXX/format-strings.cpp Tue Feb 21 14:00:53 2012
@@ -1,8 +1,11 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -pedantic %s
 
+#include <stdarg.h>
+
 extern "C" {
 extern int scanf(const char *restrict, ...);
 extern int printf(const char *restrict, ...);
+extern int vprintf(const char *restrict, va_list);
 }
 
 void f(char **sp, float *fp) {
@@ -23,11 +26,12 @@
 public:
   const char *gettext(const char *fmt) __attribute__((format_arg(2)));
 
-  int scanf(const char *restrict, ...) __attribute__((format(scanf, 2, 3)));
-  int printf(const char *restrict, ...) __attribute__((format(printf, 2, 3)));
+  int scanf(const char *, ...) __attribute__((format(scanf, 2, 3)));
+  int printf(const char *, ...) __attribute__((format(printf, 2, 3)));
+  int printf2(const char *, ...);
 
   static const char *gettext_static(const char *fmt) __attribute__((format_arg(1)));
-  static int printf_static(const char *restrict, ...) __attribute__((format(printf, 1, 2)));
+  static int printf_static(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
 };
 
 void h(int *i) {
@@ -52,3 +56,23 @@
   test_null_format(__null); // no-warning
   test_null_format(f); // expected-warning {{not a string literal}}
 }
+
+int Foo::printf(const char *fmt, ...) {
+  va_list ap;
+  va_start(ap,fmt);
+  const char * const format = fmt;
+  vprintf(format, ap); // no-warning
+
+  const char *format2 = fmt;
+  vprintf(format2, ap); // expected-warning{{format string is not a string literal}}
+
+  return 0;
+}
+
+int Foo::printf2(const char *fmt, ...) {
+  va_list ap;
+  va_start(ap,fmt);
+  vprintf(fmt, ap); // expected-warning{{format string is not a string literal}}
+
+  return 0;
+}

Modified: cfe/trunk/test/SemaObjC/format-strings-objc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/format-strings-objc.m?rev=151080&r1=151079&r2=151080&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/format-strings-objc.m (original)
+++ cfe/trunk/test/SemaObjC/format-strings-objc.m Tue Feb 21 14:00:53 2012
@@ -9,11 +9,13 @@
 // portable to non-Mac platforms.
 //===----------------------------------------------------------------------===//
 
+#include <stdarg.h>
+
 typedef signed char BOOL;
 typedef unsigned int NSUInteger;
 @class NSString, Protocol;
-extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
-extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+extern void NSLog(NSString *format, ...);
+extern void NSLogv(NSString *format, va_list args);
 typedef struct _NSZone NSZone;
 @class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
 @protocol NSObject  - (BOOL)isEqual:(id)object; @end
@@ -151,3 +153,26 @@
 void test_toll_free_bridging(CFStringRef x) {
   NSLog(@"%@", x); // no-warning
 }
+
+ at interface Bar
++ (void)log:(NSString *)fmt, ...;
++ (void)log2:(NSString *)fmt, ... __attribute__((format(NSString, 1, 2)));
+ at end
+
+ at implementation Bar
+
++ (void)log:(NSString *)fmt, ... {
+  va_list ap;
+  va_start(ap,fmt);
+  NSLogv(fmt, ap); // expected-warning{{format string is not a string literal}}
+  va_end(ap);
+}
+
++ (void)log2:(NSString *)fmt, ... {
+  va_list ap;
+  va_start(ap,fmt);
+  NSLogv(fmt, ap); // no-warning
+  va_end(ap);
+}
+
+ at end





More information about the cfe-commits mailing list