forked from OSchip/llvm-project
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.
llvm-svn: 151080
This commit is contained in:
parent
b41b407f3d
commit
58dab6829a
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue