1//==- CheckSizeofPointer.cpp - Check for sizeof on pointers ------*- C++ -*-==// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// This file defines a check for unintended use of sizeof() on pointer 10// expressions. 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 15#include "clang/AST/StmtVisitor.h" 16#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 17#include "clang/StaticAnalyzer/Core/Checker.h" 18#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 19 20using namespace clang; 21using namespace ento; 22 23namespace { 24class WalkAST : public StmtVisitor<WalkAST> { 25 BugReporter &BR; 26 const CheckerBase *Checker; 27 AnalysisDeclContext* AC; 28 29public: 30 WalkAST(BugReporter &br, const CheckerBase *checker, AnalysisDeclContext *ac) 31 : BR(br), Checker(checker), AC(ac) {} 32 void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); 33 void VisitStmt(Stmt *S) { VisitChildren(S); } 34 void VisitChildren(Stmt *S); 35}; 36} 37 38void WalkAST::VisitChildren(Stmt *S) { 39 for (Stmt *Child : S->children()) 40 if (Child) 41 Visit(Child); 42} 43 44// CWE-467: Use of sizeof() on a Pointer Type 45void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { 46 if (E->getKind() != UETT_SizeOf) 47 return; 48 49 // If an explicit type is used in the code, usually the coder knows what they are 50 // doing. 51 if (E->isArgumentType()) 52 return; 53 54 QualType T = E->getTypeOfArgument(); 55 if (T->isPointerType()) { 56 57 // Many false positives have the form 'sizeof *p'. This is reasonable 58 // because people know what they are doing when they intentionally 59 // dereference the pointer. 60 Expr *ArgEx = E->getArgumentExpr(); 61 if (!isa<DeclRefExpr>(ArgEx->IgnoreParens())) 62 return; 63 64 PathDiagnosticLocation ELoc = 65 PathDiagnosticLocation::createBegin(E, BR.getSourceManager(), AC); 66 BR.EmitBasicReport(AC->getDecl(), Checker, 67 "Potential unintended use of sizeof() on pointer type", 68 categories::LogicError, 69 "The code calls sizeof() on a pointer type. " 70 "This can produce an unexpected result.", 71 ELoc, ArgEx->getSourceRange()); 72 } 73} 74 75//===----------------------------------------------------------------------===// 76// SizeofPointerChecker 77//===----------------------------------------------------------------------===// 78 79namespace { 80class SizeofPointerChecker : public Checker<check::ASTCodeBody> { 81public: 82 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 83 BugReporter &BR) const { 84 WalkAST walker(BR, this, mgr.getAnalysisDeclContext(D)); 85 walker.Visit(D->getBody()); 86 } 87}; 88} 89 90void ento::registerSizeofPointerChecker(CheckerManager &mgr) { 91 mgr.registerChecker<SizeofPointerChecker>(); 92} 93 94bool ento::shouldRegisterSizeofPointerChecker(const CheckerManager &mgr) { 95 return true; 96} 97