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