SprintfLiteralChecker.cpp (3209B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "SprintfLiteralChecker.h" 6 #include "CustomMatchers.h" 7 8 void SprintfLiteralChecker::registerMatchers(MatchFinder *AstMatcher) { 9 AstMatcher->addMatcher( 10 callExpr( 11 isSnprintfLikeFunc(), 12 allOf(hasArgument( 13 0, ignoringParenImpCasts(declRefExpr().bind("buffer"))), 14 anyOf(hasArgument(1, sizeOfExpr(has(ignoringParenImpCasts( 15 declRefExpr().bind("size"))))), 16 hasArgument(1, integerLiteral().bind("immediate")), 17 hasArgument(1, declRefExpr(to(varDecl( 18 hasType(isConstQualified()), 19 hasInitializer(integerLiteral().bind( 20 "constant")))))))),isFirstParty()) 21 .bind("funcCall"), 22 this); 23 } 24 25 void SprintfLiteralChecker::check(const MatchFinder::MatchResult &Result) { 26 if (!Result.Context->getLangOpts().CPlusPlus) { 27 // SprintfLiteral is not usable in C, so there is no point in issuing these 28 // warnings. 29 return; 30 } 31 32 const char *Error = 33 "Use %1 instead of %0 when writing into a character array."; 34 const char *Note = 35 "This will prevent passing in the wrong size to %0 accidentally."; 36 37 const CallExpr *D = Result.Nodes.getNodeAs<CallExpr>("funcCall"); 38 39 StringRef Name = D->getDirectCallee()->getName(); 40 const char *Replacement; 41 if (Name == "snprintf") { 42 Replacement = "SprintfLiteral"; 43 } else { 44 assert(Name == "vsnprintf"); 45 Replacement = "VsprintfLiteral"; 46 } 47 48 const DeclRefExpr *Buffer = Result.Nodes.getNodeAs<DeclRefExpr>("buffer"); 49 const DeclRefExpr *Size = Result.Nodes.getNodeAs<DeclRefExpr>("size"); 50 if (Size) { 51 // Match calls like snprintf(x, sizeof(x), ...). 52 if (Buffer->getFoundDecl() != Size->getFoundDecl()) { 53 return; 54 } 55 56 diag(D->getBeginLoc(), Error, DiagnosticIDs::Error) << Name << Replacement; 57 diag(D->getBeginLoc(), Note, DiagnosticIDs::Note) << Name; 58 return; 59 } 60 61 const QualType QType = Buffer->getType(); 62 const ConstantArrayType *Type = 63 dyn_cast<ConstantArrayType>(QType.getTypePtrOrNull()); 64 if (Type) { 65 // Match calls like snprintf(x, 100, ...), where x is int[100]; 66 const IntegerLiteral *Literal = 67 Result.Nodes.getNodeAs<IntegerLiteral>("immediate"); 68 if (!Literal) { 69 // Match calls like: const int y = 100; snprintf(x, y, ...); 70 Literal = Result.Nodes.getNodeAs<IntegerLiteral>("constant"); 71 } 72 73 // We're going to assume here that the bitwidth of both of these values fits 74 // within 64 bits. and zero-extend both values to 64-bits before comparing 75 // them. 76 uint64_t Size = Type->getSize().getZExtValue(); 77 uint64_t Lit = Literal->getValue().getZExtValue(); 78 if (Size <= Lit) { 79 diag(D->getBeginLoc(), Error, DiagnosticIDs::Error) 80 << Name << Replacement; 81 diag(D->getBeginLoc(), Note, DiagnosticIDs::Note) << Name; 82 } 83 } 84 }