]> granicus.if.org Git - clang/commitdiff
When calling a non variadic format function(vprintf, vscanf, NSLogv, …), warn if...
authorJean-Daniel Dupas <devlists@shadowlab.org>
Tue, 21 Feb 2012 20:00:53 +0000 (20:00 +0000)
committerJean-Daniel Dupas <devlists@shadowlab.org>
Tue, 21 Feb 2012 20:00:53 +0000 (20:00 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151080 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaChecking.cpp
test/Sema/format-strings.c
test/SemaCXX/format-strings.cpp
test/SemaObjC/format-strings-objc.m

index 1d75ef6e6f5eac2136c4cf01ae8ccd4ee5ef6038..9454a751550d9173e80cafabb0e396581856e79d 100644 (file)
@@ -1447,13 +1447,27 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
       //      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;
index e6ce6e3c4ab8e103ea7803b2037dc3b1a6c6394e..55b8201fd39ec7c3b5918e99563be4a8c80a4022 100644 (file)
@@ -14,6 +14,8 @@ int vprintf(const char *restrict, va_list);
 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 @@ void check_string_literal( FILE* fp, const char* s, char *buf, ... ) {
   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 @@ def"
   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
index 0d5b62598d11bcd97e2725b4e38a3184b5d38a0d..74fc7a7810d97bf7ade526efdc97017551042a74 100644 (file)
@@ -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 @@ class Foo {
 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 @@ void rdar8269537(const char *f)
   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;
+}
index 675729ca1e95d50908ab881e154e531ae307ccd3..a2a926c7d010f7f13ee9ae3b86fdd61198d6f2d9 100644 (file)
@@ -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_percent_C() {
 void test_toll_free_bridging(CFStringRef x) {
   NSLog(@"%@", x); // no-warning
 }
+
+@interface Bar
++ (void)log:(NSString *)fmt, ...;
++ (void)log2:(NSString *)fmt, ... __attribute__((format(NSString, 1, 2)));
+@end
+
+@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);
+}
+
+@end