diff options
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 435b951b7c0..0c3a3df1f18 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -767,6 +767,37 @@ static void CheckNonNullArgument(Sema &S, S.Diag(CallSiteLoc, diag::warn_null_arg) << ArgExpr->getSourceRange(); } +/// \brief Diagnose use of %s directive in an NSString which is being passed +/// as formatting string to formatting method. +static void +DiagnoseCStringFormatDirectiveInCFAPI(Sema &S, + const NamedDecl *FDecl, + Expr **Args, + unsigned NumArgs) { + if (NumArgs < 3) + return; + ObjCStringFormatFamily SFFamily = FDecl->getObjCFStringFormattingFamily(); + if (SFFamily == ObjCStringFormatFamily::SFF_CFString) { + const Expr *FormatExpr = Args[2]; + if (const CStyleCastExpr *CSCE = dyn_cast<CStyleCastExpr>(FormatExpr)) + FormatExpr = CSCE->getSubExpr(); + const StringLiteral *FormatString; + if (const ObjCStringLiteral *OSL = + dyn_cast<ObjCStringLiteral>(FormatExpr->IgnoreParenImpCasts())) + FormatString = OSL->getString(); + else + FormatString = dyn_cast<StringLiteral>(FormatExpr->IgnoreParenImpCasts()); + if (!FormatString) + return; + if (S.FormatStringHasSArg(FormatString)) { + S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string) + << "%s" << 1 << 1; + S.Diag(FDecl->getLocation(), diag::note_entity_declared_at) + << FDecl->getDeclName(); + } + } +} + static void CheckNonNullArguments(Sema &S, const NamedDecl *FDecl, ArrayRef<const Expr *> Args, @@ -899,6 +930,8 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, return false; CheckAbsoluteValueFunction(TheCall, FDecl, FnInfo); + + DiagnoseCStringFormatDirectiveInCFAPI(*this, FDecl, Args, NumArgs); unsigned CMId = FDecl->getMemoryFunctionKind(); if (CMId == 0) @@ -3744,6 +3777,20 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, } // TODO: handle other formats } +bool Sema::FormatStringHasSArg(const StringLiteral *FExpr) { + // Str - The format string. NOTE: this is NOT null-terminated! + StringRef StrRef = FExpr->getString(); + const char *Str = StrRef.data(); + // Account for cases where the string literal is truncated in a declaration. + const ConstantArrayType *T = Context.getAsConstantArrayType(FExpr->getType()); + assert(T && "String literal not of constant array type!"); + size_t TypeSize = T->getSize().getZExtValue(); + size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size()); + return analyze_format_string::ParseFormatStringHasSArg(Str, Str + StrLen, + getLangOpts(), + Context.getTargetInfo()); +} + //===--- CHECK: Warn on use of wrong absolute value function. -------------===// // Returns the related absolute value function that is larger, of 0 if one |