1*0b57cec5SDimitry Andric //===- OSObjectCStyleCast.cpp ------------------------------------*- C++ -*-==// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file defines OSObjectCStyleCast checker, which checks for C-style casts 10*0b57cec5SDimitry Andric // of OSObjects. Such casts almost always indicate a code smell, 11*0b57cec5SDimitry Andric // as an explicit static or dynamic cast should be used instead. 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 15*0b57cec5SDimitry Andric #include "clang/ASTMatchers/ASTMatchFinder.h" 16*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 17*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 18*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 19*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 20*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 21*0b57cec5SDimitry Andric 22*0b57cec5SDimitry Andric using namespace clang; 23*0b57cec5SDimitry Andric using namespace ento; 24*0b57cec5SDimitry Andric using namespace ast_matchers; 25*0b57cec5SDimitry Andric 26*0b57cec5SDimitry Andric namespace { 27*0b57cec5SDimitry Andric 28*0b57cec5SDimitry Andric const char *WarnAtNode = "OSObjCast"; 29*0b57cec5SDimitry Andric 30*0b57cec5SDimitry Andric class OSObjectCStyleCastChecker : public Checker<check::ASTCodeBody> { 31*0b57cec5SDimitry Andric public: 32*0b57cec5SDimitry Andric void checkASTCodeBody(const Decl *D, 33*0b57cec5SDimitry Andric AnalysisManager &AM, 34*0b57cec5SDimitry Andric BugReporter &BR) const; 35*0b57cec5SDimitry Andric }; 36*0b57cec5SDimitry Andric 37*0b57cec5SDimitry Andric static void emitDiagnostics(const BoundNodes &Nodes, 38*0b57cec5SDimitry Andric BugReporter &BR, 39*0b57cec5SDimitry Andric AnalysisDeclContext *ADC, 40*0b57cec5SDimitry Andric const OSObjectCStyleCastChecker *Checker) { 41*0b57cec5SDimitry Andric const auto *CE = Nodes.getNodeAs<CastExpr>(WarnAtNode); 42*0b57cec5SDimitry Andric assert(CE); 43*0b57cec5SDimitry Andric 44*0b57cec5SDimitry Andric std::string Diagnostics; 45*0b57cec5SDimitry Andric llvm::raw_string_ostream OS(Diagnostics); 46*0b57cec5SDimitry Andric OS << "C-style cast of OSObject. Use OSDynamicCast instead."; 47*0b57cec5SDimitry Andric 48*0b57cec5SDimitry Andric BR.EmitBasicReport( 49*0b57cec5SDimitry Andric ADC->getDecl(), 50*0b57cec5SDimitry Andric Checker, 51*0b57cec5SDimitry Andric /*Name=*/"OSObject C-Style Cast", 52*0b57cec5SDimitry Andric /*BugCategory=*/"Security", 53*0b57cec5SDimitry Andric OS.str(), 54*0b57cec5SDimitry Andric PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), ADC), 55*0b57cec5SDimitry Andric CE->getSourceRange()); 56*0b57cec5SDimitry Andric } 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric static auto hasTypePointingTo(DeclarationMatcher DeclM) 59*0b57cec5SDimitry Andric -> decltype(hasType(pointerType())) { 60*0b57cec5SDimitry Andric return hasType(pointerType(pointee(hasDeclaration(DeclM)))); 61*0b57cec5SDimitry Andric } 62*0b57cec5SDimitry Andric 63*0b57cec5SDimitry Andric void OSObjectCStyleCastChecker::checkASTCodeBody(const Decl *D, AnalysisManager &AM, 64*0b57cec5SDimitry Andric BugReporter &BR) const { 65*0b57cec5SDimitry Andric 66*0b57cec5SDimitry Andric AnalysisDeclContext *ADC = AM.getAnalysisDeclContext(D); 67*0b57cec5SDimitry Andric 68*0b57cec5SDimitry Andric auto DynamicCastM = callExpr(callee(functionDecl(hasName("safeMetaCast")))); 69*0b57cec5SDimitry Andric 70*0b57cec5SDimitry Andric auto OSObjTypeM = hasTypePointingTo(cxxRecordDecl(isDerivedFrom("OSMetaClassBase"))); 71*0b57cec5SDimitry Andric auto OSObjSubclassM = hasTypePointingTo( 72*0b57cec5SDimitry Andric cxxRecordDecl(isDerivedFrom("OSObject"))); 73*0b57cec5SDimitry Andric 74*0b57cec5SDimitry Andric auto CastM = cStyleCastExpr( 75*0b57cec5SDimitry Andric allOf(hasSourceExpression(allOf(OSObjTypeM, unless(DynamicCastM))), 76*0b57cec5SDimitry Andric OSObjSubclassM)).bind(WarnAtNode); 77*0b57cec5SDimitry Andric 78*0b57cec5SDimitry Andric auto Matches = match(stmt(forEachDescendant(CastM)), *D->getBody(), AM.getASTContext()); 79*0b57cec5SDimitry Andric for (BoundNodes Match : Matches) 80*0b57cec5SDimitry Andric emitDiagnostics(Match, BR, ADC, this); 81*0b57cec5SDimitry Andric } 82*0b57cec5SDimitry Andric } 83*0b57cec5SDimitry Andric 84*0b57cec5SDimitry Andric void ento::registerOSObjectCStyleCast(CheckerManager &Mgr) { 85*0b57cec5SDimitry Andric Mgr.registerChecker<OSObjectCStyleCastChecker>(); 86*0b57cec5SDimitry Andric } 87*0b57cec5SDimitry Andric 88*0b57cec5SDimitry Andric bool ento::shouldRegisterOSObjectCStyleCast(const LangOptions &LO) { 89*0b57cec5SDimitry Andric return true; 90*0b57cec5SDimitry Andric } 91