Bug 1890277: part 2) Add `require-trusted-types-for` directive to CSP parser, guarded...
[gecko.git] / build / clang-plugin / SprintfLiteralChecker.cpp
blob94e8e2fd1b7f5ed8d9e7ef5245885f3525afc864
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(
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")))))))))
21 .bind("funcCall"),
22 this);
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;
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.";
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";
43 } else {
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");
50 if (Size) {
51 // Match calls like snprintf(x, sizeof(x), ...).
52 if (Buffer->getFoundDecl() != Size->getFoundDecl()) {
53 return;
56 diag(D->getBeginLoc(), Error, DiagnosticIDs::Error) << Name << Replacement;
57 diag(D->getBeginLoc(), Note, DiagnosticIDs::Note) << Name;
58 return;
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");
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;