diff options
-rw-r--r-- | lib/Sema/Sema.h | 5 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 62 | ||||
-rw-r--r-- | test/Sema/format-strings.c | 6 |
3 files changed, 64 insertions, 9 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index f098372d97..fc619c6f1f 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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, diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 5bb78cd765..ff9d75302f 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -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(), diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c index 16d4943cda..19c29db343 100644 --- a/test/Sema/format-strings.c +++ b/test/Sema/format-strings.c @@ -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; |