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/. */
5 #include "SprintfLiteralChecker.h"
6 #include "CustomMatchers.h"
8 void SprintfLiteralChecker::registerMatchers(MatchFinder
*AstMatcher
) {
9 AstMatcher
->addMatcher(
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(
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
33 "Use %1 instead of %0 when writing into a character array.";
35 "This will prevent passing in the wrong size to %0 accidentally.";
37 const CallExpr
*D
= Result
.Nodes
.getNodeAs
<CallExpr
>("funcCall");
39 StringRef Name
= D
->getDirectCallee()->getName();
40 const char *Replacement
;
41 if (Name
== "snprintf") {
42 Replacement
= "SprintfLiteral";
44 assert(Name
== "vsnprintf");
45 Replacement
= "VsprintfLiteral";
48 const DeclRefExpr
*Buffer
= Result
.Nodes
.getNodeAs
<DeclRefExpr
>("buffer");
49 const DeclRefExpr
*Size
= Result
.Nodes
.getNodeAs
<DeclRefExpr
>("size");
51 // Match calls like snprintf(x, sizeof(x), ...).
52 if (Buffer
->getFoundDecl() != Size
->getFoundDecl()) {
56 diag(D
->getBeginLoc(), Error
, DiagnosticIDs::Error
) << Name
<< Replacement
;
57 diag(D
->getBeginLoc(), Note
, DiagnosticIDs::Note
) << Name
;
61 const QualType QType
= Buffer
->getType();
62 const ConstantArrayType
*Type
=
63 dyn_cast
<ConstantArrayType
>(QType
.getTypePtrOrNull());
65 // Match calls like snprintf(x, 100, ...), where x is int[100];
66 const IntegerLiteral
*Literal
=
67 Result
.Nodes
.getNodeAs
<IntegerLiteral
>("immediate");
69 // Match calls like: const int y = 100; snprintf(x, y, ...);
70 Literal
= Result
.Nodes
.getNodeAs
<IntegerLiteral
>("constant");
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
76 uint64_t Size
= Type
->getSize().getZExtValue();
77 uint64_t Lit
= Literal
->getValue().getZExtValue();
79 diag(D
->getBeginLoc(), Error
, DiagnosticIDs::Error
)
80 << Name
<< Replacement
;
81 diag(D
->getBeginLoc(), Note
, DiagnosticIDs::Note
) << Name
;