12754fe60SDimitry Andric //==- CheckSizeofPointer.cpp - Check for sizeof on pointers ------*- C++ -*-==//
22754fe60SDimitry Andric //
32754fe60SDimitry Andric // The LLVM Compiler Infrastructure
42754fe60SDimitry Andric //
52754fe60SDimitry Andric // This file is distributed under the University of Illinois Open Source
62754fe60SDimitry Andric // License. See LICENSE.TXT for details.
72754fe60SDimitry Andric //
82754fe60SDimitry Andric //===----------------------------------------------------------------------===//
92754fe60SDimitry Andric //
102754fe60SDimitry Andric // This file defines a check for unintended use of sizeof() on pointer
112754fe60SDimitry Andric // expressions.
122754fe60SDimitry Andric //
132754fe60SDimitry Andric //===----------------------------------------------------------------------===//
142754fe60SDimitry Andric
15*b5893f02SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
166122f3e6SDimitry Andric #include "clang/AST/StmtVisitor.h"
172754fe60SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
18139f7f9bSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
196122f3e6SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
202754fe60SDimitry Andric
212754fe60SDimitry Andric using namespace clang;
222754fe60SDimitry Andric using namespace ento;
232754fe60SDimitry Andric
242754fe60SDimitry Andric namespace {
252754fe60SDimitry Andric class WalkAST : public StmtVisitor<WalkAST> {
262754fe60SDimitry Andric BugReporter &BR;
2759d1ed5bSDimitry Andric const CheckerBase *Checker;
28dff0c46cSDimitry Andric AnalysisDeclContext* AC;
292754fe60SDimitry Andric
302754fe60SDimitry Andric public:
WalkAST(BugReporter & br,const CheckerBase * checker,AnalysisDeclContext * ac)3159d1ed5bSDimitry Andric WalkAST(BugReporter &br, const CheckerBase *checker, AnalysisDeclContext *ac)
3259d1ed5bSDimitry Andric : BR(br), Checker(checker), AC(ac) {}
333b0f4066SDimitry Andric void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
VisitStmt(Stmt * S)342754fe60SDimitry Andric void VisitStmt(Stmt *S) { VisitChildren(S); }
352754fe60SDimitry Andric void VisitChildren(Stmt *S);
362754fe60SDimitry Andric };
372754fe60SDimitry Andric }
382754fe60SDimitry Andric
VisitChildren(Stmt * S)392754fe60SDimitry Andric void WalkAST::VisitChildren(Stmt *S) {
403dac3a9bSDimitry Andric for (Stmt *Child : S->children())
413dac3a9bSDimitry Andric if (Child)
423dac3a9bSDimitry Andric Visit(Child);
432754fe60SDimitry Andric }
442754fe60SDimitry Andric
452754fe60SDimitry Andric // CWE-467: Use of sizeof() on a Pointer Type
VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr * E)463b0f4066SDimitry Andric void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
473b0f4066SDimitry Andric if (E->getKind() != UETT_SizeOf)
482754fe60SDimitry Andric return;
492754fe60SDimitry Andric
5059d1ed5bSDimitry Andric // If an explicit type is used in the code, usually the coder knows what they are
512754fe60SDimitry Andric // doing.
522754fe60SDimitry Andric if (E->isArgumentType())
532754fe60SDimitry Andric return;
542754fe60SDimitry Andric
552754fe60SDimitry Andric QualType T = E->getTypeOfArgument();
562754fe60SDimitry Andric if (T->isPointerType()) {
572754fe60SDimitry Andric
582754fe60SDimitry Andric // Many false positives have the form 'sizeof *p'. This is reasonable
592754fe60SDimitry Andric // because people know what they are doing when they intentionally
602754fe60SDimitry Andric // dereference the pointer.
612754fe60SDimitry Andric Expr *ArgEx = E->getArgumentExpr();
622754fe60SDimitry Andric if (!isa<DeclRefExpr>(ArgEx->IgnoreParens()))
632754fe60SDimitry Andric return;
642754fe60SDimitry Andric
656122f3e6SDimitry Andric PathDiagnosticLocation ELoc =
666122f3e6SDimitry Andric PathDiagnosticLocation::createBegin(E, BR.getSourceManager(), AC);
6759d1ed5bSDimitry Andric BR.EmitBasicReport(AC->getDecl(), Checker,
68dff0c46cSDimitry Andric "Potential unintended use of sizeof() on pointer type",
69f785676fSDimitry Andric categories::LogicError,
702754fe60SDimitry Andric "The code calls sizeof() on a pointer type. "
712754fe60SDimitry Andric "This can produce an unexpected result.",
72f785676fSDimitry Andric ELoc, ArgEx->getSourceRange());
732754fe60SDimitry Andric }
742754fe60SDimitry Andric }
752754fe60SDimitry Andric
762754fe60SDimitry Andric //===----------------------------------------------------------------------===//
772754fe60SDimitry Andric // SizeofPointerChecker
782754fe60SDimitry Andric //===----------------------------------------------------------------------===//
792754fe60SDimitry Andric
802754fe60SDimitry Andric namespace {
813b0f4066SDimitry Andric class SizeofPointerChecker : public Checker<check::ASTCodeBody> {
822754fe60SDimitry Andric public:
checkASTCodeBody(const Decl * D,AnalysisManager & mgr,BugReporter & BR) const832754fe60SDimitry Andric void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
842754fe60SDimitry Andric BugReporter &BR) const {
8559d1ed5bSDimitry Andric WalkAST walker(BR, this, mgr.getAnalysisDeclContext(D));
862754fe60SDimitry Andric walker.Visit(D->getBody());
872754fe60SDimitry Andric }
882754fe60SDimitry Andric };
892754fe60SDimitry Andric }
902754fe60SDimitry Andric
registerSizeofPointerChecker(CheckerManager & mgr)912754fe60SDimitry Andric void ento::registerSizeofPointerChecker(CheckerManager &mgr) {
922754fe60SDimitry Andric mgr.registerChecker<SizeofPointerChecker>();
932754fe60SDimitry Andric }
94