OSObjectCStyleCast.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. //===- OSObjectCStyleCast.cpp ------------------------------------*- 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 OSObjectCStyleCast checker, which checks for C-style casts
  10. // of OSObjects. Such casts almost always indicate a code smell,
  11. // as an explicit static or dynamic cast should be used instead.
  12. //===----------------------------------------------------------------------===//
  13. #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
  14. #include "clang/ASTMatchers/ASTMatchFinder.h"
  15. #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
  16. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  17. #include "clang/StaticAnalyzer/Core/Checker.h"
  18. #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
  19. #include "llvm/Support/Debug.h"
  20. using namespace clang;
  21. using namespace ento;
  22. using namespace ast_matchers;
  23. namespace {
  24. const char *WarnAtNode = "OSObjCast";
  25. class OSObjectCStyleCastChecker : public Checker<check::ASTCodeBody> {
  26. public:
  27. void checkASTCodeBody(const Decl *D,
  28. AnalysisManager &AM,
  29. BugReporter &BR) const;
  30. };
  31. static void emitDiagnostics(const BoundNodes &Nodes,
  32. BugReporter &BR,
  33. AnalysisDeclContext *ADC,
  34. const OSObjectCStyleCastChecker *Checker) {
  35. const auto *CE = Nodes.getNodeAs<CastExpr>(WarnAtNode);
  36. assert(CE);
  37. std::string Diagnostics;
  38. llvm::raw_string_ostream OS(Diagnostics);
  39. OS << "C-style cast of OSObject. Use OSDynamicCast instead.";
  40. BR.EmitBasicReport(
  41. ADC->getDecl(),
  42. Checker,
  43. /*Name=*/"OSObject C-Style Cast",
  44. /*BugCategory=*/"Security",
  45. OS.str(),
  46. PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), ADC),
  47. CE->getSourceRange());
  48. }
  49. static auto hasTypePointingTo(DeclarationMatcher DeclM)
  50. -> decltype(hasType(pointerType())) {
  51. return hasType(pointerType(pointee(hasDeclaration(DeclM))));
  52. }
  53. void OSObjectCStyleCastChecker::checkASTCodeBody(const Decl *D, AnalysisManager &AM,
  54. BugReporter &BR) const {
  55. AnalysisDeclContext *ADC = AM.getAnalysisDeclContext(D);
  56. auto DynamicCastM = callExpr(callee(functionDecl(hasName("safeMetaCast"))));
  57. auto OSObjTypeM = hasTypePointingTo(cxxRecordDecl(isDerivedFrom("OSMetaClassBase")));
  58. auto OSObjSubclassM = hasTypePointingTo(
  59. cxxRecordDecl(isDerivedFrom("OSObject")));
  60. auto CastM = cStyleCastExpr(
  61. allOf(hasSourceExpression(allOf(OSObjTypeM, unless(DynamicCastM))),
  62. OSObjSubclassM)).bind(WarnAtNode);
  63. auto Matches = match(stmt(forEachDescendant(CastM)), *D->getBody(), AM.getASTContext());
  64. for (BoundNodes Match : Matches)
  65. emitDiagnostics(Match, BR, ADC, this);
  66. }
  67. }
  68. void ento::registerOSObjectCStyleCast(CheckerManager &Mgr) {
  69. Mgr.registerChecker<OSObjectCStyleCastChecker>();
  70. }
  71. bool ento::shouldRegisterOSObjectCStyleCast(const LangOptions &LO) {
  72. return true;
  73. }