1d99bd55aSTed Kremenek //==- CheckSizeofPointer.cpp - Check for sizeof on pointers ------*- C++ -*-==//
2d99bd55aSTed Kremenek //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d99bd55aSTed Kremenek //
7d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
8d99bd55aSTed Kremenek //
9d99bd55aSTed Kremenek // This file defines a check for unintended use of sizeof() on pointer
10d99bd55aSTed Kremenek // expressions.
11d99bd55aSTed Kremenek //
12d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
13d99bd55aSTed Kremenek
1476a21502SKristof Umann #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15c29bed39SAnna Zaks #include "clang/AST/StmtVisitor.h"
16f8cbac4bSTed Kremenek #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
173a02247dSChandler Carruth #include "clang/StaticAnalyzer/Core/Checker.h"
18c29bed39SAnna Zaks #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
19d99bd55aSTed Kremenek
20d99bd55aSTed Kremenek using namespace clang;
21d99bd55aSTed Kremenek using namespace ento;
22d99bd55aSTed Kremenek
23d99bd55aSTed Kremenek namespace {
24d99bd55aSTed Kremenek class WalkAST : public StmtVisitor<WalkAST> {
25d99bd55aSTed Kremenek BugReporter &BR;
264aca9b1cSAlexander Kornienko const CheckerBase *Checker;
2781ce1c8aSTed Kremenek AnalysisDeclContext* AC;
28d99bd55aSTed Kremenek
29d99bd55aSTed Kremenek public:
WalkAST(BugReporter & br,const CheckerBase * checker,AnalysisDeclContext * ac)304aca9b1cSAlexander Kornienko WalkAST(BugReporter &br, const CheckerBase *checker, AnalysisDeclContext *ac)
314aca9b1cSAlexander Kornienko : BR(br), Checker(checker), AC(ac) {}
32e190dee7SPeter Collingbourne void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
VisitStmt(Stmt * S)33d99bd55aSTed Kremenek void VisitStmt(Stmt *S) { VisitChildren(S); }
34d99bd55aSTed Kremenek void VisitChildren(Stmt *S);
35d99bd55aSTed Kremenek };
36ab9db510SAlexander Kornienko }
37d99bd55aSTed Kremenek
VisitChildren(Stmt * S)38d99bd55aSTed Kremenek void WalkAST::VisitChildren(Stmt *S) {
39973431b2SBenjamin Kramer for (Stmt *Child : S->children())
40973431b2SBenjamin Kramer if (Child)
41973431b2SBenjamin Kramer Visit(Child);
42d99bd55aSTed Kremenek }
43d99bd55aSTed Kremenek
44d99bd55aSTed Kremenek // CWE-467: Use of sizeof() on a Pointer Type
VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr * E)45e190dee7SPeter Collingbourne void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
46e190dee7SPeter Collingbourne if (E->getKind() != UETT_SizeOf)
47d99bd55aSTed Kremenek return;
48d99bd55aSTed Kremenek
49c9e2a689SEric Christopher // If an explicit type is used in the code, usually the coder knows what they are
50d99bd55aSTed Kremenek // doing.
51d99bd55aSTed Kremenek if (E->isArgumentType())
52d99bd55aSTed Kremenek return;
53d99bd55aSTed Kremenek
54d99bd55aSTed Kremenek QualType T = E->getTypeOfArgument();
55d99bd55aSTed Kremenek if (T->isPointerType()) {
56d99bd55aSTed Kremenek
57d99bd55aSTed Kremenek // Many false positives have the form 'sizeof *p'. This is reasonable
58d99bd55aSTed Kremenek // because people know what they are doing when they intentionally
59d99bd55aSTed Kremenek // dereference the pointer.
60d99bd55aSTed Kremenek Expr *ArgEx = E->getArgumentExpr();
61d99bd55aSTed Kremenek if (!isa<DeclRefExpr>(ArgEx->IgnoreParens()))
62d99bd55aSTed Kremenek return;
63d99bd55aSTed Kremenek
64c29bed39SAnna Zaks PathDiagnosticLocation ELoc =
65c29bed39SAnna Zaks PathDiagnosticLocation::createBegin(E, BR.getSourceManager(), AC);
664aca9b1cSAlexander Kornienko BR.EmitBasicReport(AC->getDecl(), Checker,
675a10f08bSTed Kremenek "Potential unintended use of sizeof() on pointer type",
686feda287SJordan Rose categories::LogicError,
69d99bd55aSTed Kremenek "The code calls sizeof() on a pointer type. "
70d99bd55aSTed Kremenek "This can produce an unexpected result.",
7142b4248fSJordan Rose ELoc, ArgEx->getSourceRange());
72d99bd55aSTed Kremenek }
73d99bd55aSTed Kremenek }
74d99bd55aSTed Kremenek
75af45aca6SArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
76af45aca6SArgyrios Kyrtzidis // SizeofPointerChecker
77af45aca6SArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
78af45aca6SArgyrios Kyrtzidis
79af45aca6SArgyrios Kyrtzidis namespace {
806a5674ffSArgyrios Kyrtzidis class SizeofPointerChecker : public Checker<check::ASTCodeBody> {
81af45aca6SArgyrios Kyrtzidis public:
checkASTCodeBody(const Decl * D,AnalysisManager & mgr,BugReporter & BR) const82af45aca6SArgyrios Kyrtzidis void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
83af45aca6SArgyrios Kyrtzidis BugReporter &BR) const {
844aca9b1cSAlexander Kornienko WalkAST walker(BR, this, mgr.getAnalysisDeclContext(D));
85d99bd55aSTed Kremenek walker.Visit(D->getBody());
86d99bd55aSTed Kremenek }
87af45aca6SArgyrios Kyrtzidis };
88af45aca6SArgyrios Kyrtzidis }
89af45aca6SArgyrios Kyrtzidis
registerSizeofPointerChecker(CheckerManager & mgr)90af45aca6SArgyrios Kyrtzidis void ento::registerSizeofPointerChecker(CheckerManager &mgr) {
91af45aca6SArgyrios Kyrtzidis mgr.registerChecker<SizeofPointerChecker>();
92af45aca6SArgyrios Kyrtzidis }
93058a7a45SKristof Umann
shouldRegisterSizeofPointerChecker(const CheckerManager & mgr)94*bda3dd0dSKirstóf Umann bool ento::shouldRegisterSizeofPointerChecker(const CheckerManager &mgr) {
95058a7a45SKristof Umann return true;
96058a7a45SKristof Umann }
97