xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/OSObjectCStyleCast.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
10b57cec5SDimitry Andric //===- OSObjectCStyleCast.cpp ------------------------------------*- C++ -*-==//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines OSObjectCStyleCast checker, which checks for C-style casts
100b57cec5SDimitry Andric // of OSObjects. Such casts almost always indicate a code smell,
110b57cec5SDimitry Andric // as an explicit static or dynamic cast should be used instead.
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
150b57cec5SDimitry Andric #include "clang/ASTMatchers/ASTMatchFinder.h"
160b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
170b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
180b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
190b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
200b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric using namespace clang;
230b57cec5SDimitry Andric using namespace ento;
240b57cec5SDimitry Andric using namespace ast_matchers;
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric namespace {
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric const char *WarnAtNode = "OSObjCast";
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric class OSObjectCStyleCastChecker : public Checker<check::ASTCodeBody> {
310b57cec5SDimitry Andric public:
320b57cec5SDimitry Andric   void checkASTCodeBody(const Decl *D,
330b57cec5SDimitry Andric                         AnalysisManager &AM,
340b57cec5SDimitry Andric                         BugReporter &BR) const;
350b57cec5SDimitry Andric };
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric static void emitDiagnostics(const BoundNodes &Nodes,
380b57cec5SDimitry Andric                             BugReporter &BR,
390b57cec5SDimitry Andric                             AnalysisDeclContext *ADC,
400b57cec5SDimitry Andric                             const OSObjectCStyleCastChecker *Checker) {
410b57cec5SDimitry Andric   const auto *CE = Nodes.getNodeAs<CastExpr>(WarnAtNode);
420b57cec5SDimitry Andric   assert(CE);
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric   std::string Diagnostics;
450b57cec5SDimitry Andric   llvm::raw_string_ostream OS(Diagnostics);
460b57cec5SDimitry Andric   OS << "C-style cast of OSObject. Use OSDynamicCast instead.";
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric   BR.EmitBasicReport(
490b57cec5SDimitry Andric     ADC->getDecl(),
500b57cec5SDimitry Andric     Checker,
510b57cec5SDimitry Andric     /*Name=*/"OSObject C-Style Cast",
520b57cec5SDimitry Andric     /*BugCategory=*/"Security",
530b57cec5SDimitry Andric     OS.str(),
540b57cec5SDimitry Andric     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), ADC),
550b57cec5SDimitry Andric     CE->getSourceRange());
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric 
58*5ffd83dbSDimitry Andric static decltype(auto) hasTypePointingTo(DeclarationMatcher DeclM) {
590b57cec5SDimitry Andric   return hasType(pointerType(pointee(hasDeclaration(DeclM))));
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric void OSObjectCStyleCastChecker::checkASTCodeBody(const Decl *D, AnalysisManager &AM,
630b57cec5SDimitry Andric                                                  BugReporter &BR) const {
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric   AnalysisDeclContext *ADC = AM.getAnalysisDeclContext(D);
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   auto DynamicCastM = callExpr(callee(functionDecl(hasName("safeMetaCast"))));
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   auto OSObjTypeM = hasTypePointingTo(cxxRecordDecl(isDerivedFrom("OSMetaClassBase")));
700b57cec5SDimitry Andric   auto OSObjSubclassM = hasTypePointingTo(
710b57cec5SDimitry Andric     cxxRecordDecl(isDerivedFrom("OSObject")));
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   auto CastM = cStyleCastExpr(
740b57cec5SDimitry Andric           allOf(hasSourceExpression(allOf(OSObjTypeM, unless(DynamicCastM))),
750b57cec5SDimitry Andric           OSObjSubclassM)).bind(WarnAtNode);
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric   auto Matches = match(stmt(forEachDescendant(CastM)), *D->getBody(), AM.getASTContext());
780b57cec5SDimitry Andric   for (BoundNodes Match : Matches)
790b57cec5SDimitry Andric     emitDiagnostics(Match, BR, ADC, this);
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric void ento::registerOSObjectCStyleCast(CheckerManager &Mgr) {
840b57cec5SDimitry Andric   Mgr.registerChecker<OSObjectCStyleCastChecker>();
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric 
87*5ffd83dbSDimitry Andric bool ento::shouldRegisterOSObjectCStyleCast(const CheckerManager &mgr) {
880b57cec5SDimitry Andric   return true;
890b57cec5SDimitry Andric }
90