From 7ff22b259d4d4729f701679e3a7f0e242365e07f Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Mon, 16 Jun 2008 18:00:42 +0000 Subject: [PATCH] Introduce preliminary support for NSString format-string checking. Patch by Nikita Zhuk! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@52336 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/ParseAST.cpp | 2 ++ lib/Sema/Sema.cpp | 1 + lib/Sema/Sema.h | 1 + lib/Sema/SemaChecking.cpp | 36 ++++++++++++++++++++++++++++++++++-- 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp index 67b6546637..dce577bc4c 100644 --- a/lib/Sema/ParseAST.cpp +++ b/lib/Sema/ParseAST.cpp @@ -39,6 +39,8 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, bool PrintStats) { PP.getIdentifierTable(), PP.getSelectorTable()); TranslationUnit TU(Context); + TU.SetOwnsDecls(false); + Sema S(PP, Context, *Consumer); Parser P(PP, S); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 3861d04bf0..78cc5d85af 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -85,6 +85,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer) KnownFunctionIDs[id_sprintf] = &IT.get("sprintf"); KnownFunctionIDs[id_snprintf] = &IT.get("snprintf"); KnownFunctionIDs[id_asprintf] = &IT.get("asprintf"); + KnownFunctionIDs[id_NSLog] = &IT.get("NSLog"); KnownFunctionIDs[id_vsnprintf] = &IT.get("vsnprintf"); KnownFunctionIDs[id_vasprintf] = &IT.get("vasprintf"); KnownFunctionIDs[id_vfprintf] = &IT.get("vfprintf"); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index a86bc6b62b..64ab911733 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -124,6 +124,7 @@ class Sema : public Action { id_sprintf, id_snprintf, id_asprintf, + id_NSLog, id_vsnprintf, id_vasprintf, id_vfprintf, diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 63c1635ef2..7c0ff47a60 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -17,6 +17,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Basic/SourceManager.h" @@ -86,6 +87,7 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCallRaw) { case id_sprintf: format_idx = 1; break; case id_snprintf: format_idx = 2; break; case id_asprintf: format_idx = 1; break; + case id_NSLog: format_idx = 0; break; case id_vsnprintf: format_idx = 2; HasVAListArg = true; break; case id_vasprintf: format_idx = 1; HasVAListArg = true; break; case id_vfprintf: format_idx = 1; HasVAListArg = true; break; @@ -361,7 +363,19 @@ Sema::CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg, // are string literals: (1) permits the checking of format strings by // the compiler and thereby (2) can practically remove the source of // many format string exploits. - StringLiteral *FExpr = dyn_cast(OrigFormatExpr); + + // Format string can be either ObjC string (e.g. @"%d") or + // 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(OrigFormatExpr); + StringLiteral *FExpr = NULL; + + if(ObjCFExpr != NULL) + FExpr = ObjCFExpr->getString(); + else + FExpr = dyn_cast(OrigFormatExpr); + if (FExpr == NULL) { // For vprintf* functions (i.e., HasVAListArg==true), we add a // special check to see if the format string is a function parameter @@ -540,7 +554,25 @@ Sema::CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg, Diag(Loc, diag::warn_printf_write_back, Fn->getSourceRange()); break; } - + + // Handle "%@" + case '@': + // %@ is allowed in ObjC format strings only. + if(ObjCFExpr != NULL) + CurrentState = state_OrdChr; + else { + // Issue a warning: invalid format conversion. + SourceLocation Loc = PP.AdvanceToTokenCharacter(FExpr->getLocStart(), + LastConversionIdx+1); + + Diag(Loc, diag::warn_printf_invalid_conversion, + std::string(Str+LastConversionIdx, + Str+std::min(LastConversionIdx+2, StrLen)), + Fn->getSourceRange()); + } + ++numConversions; + break; + // Handle "%%" case '%': // Sanity check: Was the first "%" character the previous one? -- 2.40.0