1218887Sdim//==- CheckSizeofPointer.cpp - Check for sizeof on pointers ------*- C++ -*-==// 2218887Sdim// 3218887Sdim// The LLVM Compiler Infrastructure 4218887Sdim// 5218887Sdim// This file is distributed under the University of Illinois Open Source 6218887Sdim// License. See LICENSE.TXT for details. 7218887Sdim// 8218887Sdim//===----------------------------------------------------------------------===// 9218887Sdim// 10218887Sdim// This file defines a check for unintended use of sizeof() on pointer 11218887Sdim// expressions. 12218887Sdim// 13218887Sdim//===----------------------------------------------------------------------===// 14218887Sdim 15218887Sdim#include "ClangSACheckers.h" 16226633Sdim#include "clang/AST/StmtVisitor.h" 17249423Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 18221345Sdim#include "clang/StaticAnalyzer/Core/Checker.h" 19226633Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 20218887Sdim 21218887Sdimusing namespace clang; 22218887Sdimusing namespace ento; 23218887Sdim 24218887Sdimnamespace { 25218887Sdimclass WalkAST : public StmtVisitor<WalkAST> { 26218887Sdim BugReporter &BR; 27234353Sdim AnalysisDeclContext* AC; 28218887Sdim 29218887Sdimpublic: 30234353Sdim WalkAST(BugReporter &br, AnalysisDeclContext* ac) : BR(br), AC(ac) {} 31221345Sdim void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); 32218887Sdim void VisitStmt(Stmt *S) { VisitChildren(S); } 33218887Sdim void VisitChildren(Stmt *S); 34218887Sdim}; 35218887Sdim} 36218887Sdim 37218887Sdimvoid WalkAST::VisitChildren(Stmt *S) { 38218887Sdim for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I) 39218887Sdim if (Stmt *child = *I) 40218887Sdim Visit(child); 41218887Sdim} 42218887Sdim 43218887Sdim// CWE-467: Use of sizeof() on a Pointer Type 44221345Sdimvoid WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { 45221345Sdim if (E->getKind() != UETT_SizeOf) 46218887Sdim return; 47218887Sdim 48218887Sdim // If an explicit type is used in the code, usually the coder knows what he is 49218887Sdim // doing. 50218887Sdim if (E->isArgumentType()) 51218887Sdim return; 52218887Sdim 53218887Sdim QualType T = E->getTypeOfArgument(); 54218887Sdim if (T->isPointerType()) { 55218887Sdim 56218887Sdim // Many false positives have the form 'sizeof *p'. This is reasonable 57218887Sdim // because people know what they are doing when they intentionally 58218887Sdim // dereference the pointer. 59218887Sdim Expr *ArgEx = E->getArgumentExpr(); 60218887Sdim if (!isa<DeclRefExpr>(ArgEx->IgnoreParens())) 61218887Sdim return; 62218887Sdim 63218887Sdim SourceRange R = ArgEx->getSourceRange(); 64226633Sdim PathDiagnosticLocation ELoc = 65226633Sdim PathDiagnosticLocation::createBegin(E, BR.getSourceManager(), AC); 66234353Sdim BR.EmitBasicReport(AC->getDecl(), 67234353Sdim "Potential unintended use of sizeof() on pointer type", 68218887Sdim "Logic", 69218887Sdim "The code calls sizeof() on a pointer type. " 70218887Sdim "This can produce an unexpected result.", 71226633Sdim ELoc, &R, 1); 72218887Sdim } 73218887Sdim} 74218887Sdim 75218887Sdim//===----------------------------------------------------------------------===// 76218887Sdim// SizeofPointerChecker 77218887Sdim//===----------------------------------------------------------------------===// 78218887Sdim 79218887Sdimnamespace { 80221345Sdimclass SizeofPointerChecker : public Checker<check::ASTCodeBody> { 81218887Sdimpublic: 82218887Sdim void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 83218887Sdim BugReporter &BR) const { 84234353Sdim WalkAST walker(BR, mgr.getAnalysisDeclContext(D)); 85218887Sdim walker.Visit(D->getBody()); 86218887Sdim } 87218887Sdim}; 88218887Sdim} 89218887Sdim 90218887Sdimvoid ento::registerSizeofPointerChecker(CheckerManager &mgr) { 91218887Sdim mgr.registerChecker<SizeofPointerChecker>(); 92218887Sdim} 93