clang  13.0.0git
OSObjectCStyleCast.cpp
Go to the documentation of this file.
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 
20 #include "llvm/Support/Debug.h"
21 
22 using namespace clang;
23 using namespace ento;
24 using namespace ast_matchers;
25 
26 namespace {
27 static constexpr const char *const WarnAtNode = "WarnAtNode";
28 static constexpr const char *const WarnRecordDecl = "WarnRecordDecl";
29 
30 class OSObjectCStyleCastChecker : public Checker<check::ASTCodeBody> {
31 public:
32  void checkASTCodeBody(const Decl *D, AnalysisManager &AM,
33  BugReporter &BR) const;
34 };
35 }
36 
37 static void emitDiagnostics(const BoundNodes &Nodes,
38  BugReporter &BR,
40  const OSObjectCStyleCastChecker *Checker) {
41  const auto *CE = Nodes.getNodeAs<CastExpr>(WarnAtNode);
42  const CXXRecordDecl *RD = Nodes.getNodeAs<CXXRecordDecl>(WarnRecordDecl);
43  assert(CE && RD);
44 
45  std::string Diagnostics;
46  llvm::raw_string_ostream OS(Diagnostics);
47  OS << "C-style cast of an OSObject is prone to type confusion attacks; "
48  << "use 'OSRequiredCast' if the object is definitely of type '"
49  << RD->getNameAsString() << "', or 'OSDynamicCast' followed by "
50  << "a null check if unsure",
51 
52  BR.EmitBasicReport(
53  ADC->getDecl(),
54  Checker,
55  /*Name=*/"OSObject C-Style Cast",
57  OS.str(),
58  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), ADC),
59  CE->getSourceRange());
60 }
61 
62 static decltype(auto) hasTypePointingTo(DeclarationMatcher DeclM) {
63  return hasType(pointerType(pointee(hasDeclaration(DeclM))));
64 }
65 
66 void OSObjectCStyleCastChecker::checkASTCodeBody(const Decl *D, AnalysisManager &AM,
67  BugReporter &BR) const {
68 
69  AnalysisDeclContext *ADC = AM.getAnalysisDeclContext(D);
70 
71  auto DynamicCastM = callExpr(callee(functionDecl(hasName("safeMetaCast"))));
72 
73  auto OSObjTypeM = hasTypePointingTo(cxxRecordDecl(isDerivedFrom("OSMetaClassBase")));
74  auto OSObjSubclassM = hasTypePointingTo(
75  cxxRecordDecl(isDerivedFrom("OSObject")).bind(WarnRecordDecl));
76 
77  auto CastM = cStyleCastExpr(
78  allOf(hasSourceExpression(allOf(OSObjTypeM, unless(DynamicCastM))),
79  OSObjSubclassM)).bind(WarnAtNode);
80 
81  auto Matches = match(stmt(forEachDescendant(CastM)), *D->getBody(), AM.getASTContext());
82  for (BoundNodes Match : Matches)
83  emitDiagnostics(Match, BR, ADC, this);
84 }
85 
86 void ento::registerOSObjectCStyleCast(CheckerManager &Mgr) {
87  Mgr.registerChecker<OSObjectCStyleCastChecker>();
88 }
89 
90 bool ento::shouldRegisterOSObjectCStyleCast(const CheckerManager &mgr) {
91  return true;
92 }
clang::ast_matchers::hasDeclaration
internal::PolymorphicMatcherWithParam1< internal::HasDeclarationMatcher, internal::Matcher< Decl >, void(internal::HasDeclarationSupportedTypes)> hasDeclaration(const internal::Matcher< Decl > &InnerMatcher)
Matches a node if the declaration associated with that node matches the given matcher.
Definition: ASTMatchers.h:3512
Nodes
BoundNodesTreeBuilder Nodes
Definition: ASTMatchFinder.cpp:82
clang::ast_matchers::stmt
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
Definition: ASTMatchersInternal.cpp:795
clang::AnalysisDeclContext
AnalysisDeclContext contains the context data for the function, method or block under analysis.
Definition: AnalysisDeclContext.h:72
hasTypePointingTo
static decltype(auto) hasTypePointingTo(DeclarationMatcher DeclM)
Definition: OSObjectCStyleCast.cpp:62
clang::ast_matchers::allOf
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> allOf
Matches if all given matchers match.
Definition: ASTMatchersInternal.cpp:969
ASTMatchFinder.h
clang::ast_matchers::forEachDescendant
const internal::ArgumentAdaptingMatcherFunc< internal::ForEachDescendantMatcher > forEachDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher.
Definition: ASTMatchersInternal.cpp:991
emitDiagnostics
static void emitDiagnostics(const BoundNodes &Nodes, BugReporter &BR, AnalysisDeclContext *ADC, const OSObjectCStyleCastChecker *Checker)
Definition: OSObjectCStyleCast.cpp:37
BuiltinCheckerRegistration.h
clang::ento::categories::SecurityError
const char *const SecurityError
Definition: CommonBugCategories.cpp:24
BugReporter.h
clang::ast_matchers::unless
const internal::VariadicOperatorMatcherFunc< 1, 1 > unless
Matches if the provided matcher does not match.
Definition: ASTMatchersInternal.cpp:1002
clang::ast_matchers::cStyleCastExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, CStyleCastExpr > cStyleCastExpr
Matches a C-style cast expression.
Definition: ASTMatchersInternal.cpp:947
clang::CXXRecordDecl
Represents a C++ struct/union/class.
Definition: DeclCXX.h:254
BugType.h
clang::Decl
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:89
clang::ast_matchers::callExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
Definition: ASTMatchersInternal.cpp:802
clang::ast_matchers::functionDecl
const internal::VariadicDynCastAllOfMatcher< Decl, FunctionDecl > functionDecl
Matches function declarations.
Definition: ASTMatchersInternal.cpp:791
clang::Decl::getBody
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Definition: DeclBase.h:1010
Checker.h
clang::ast_matchers::pointerType
const AstTypeMatcher< PointerType > pointerType
Matches pointer types, but does not match Objective-C object pointer types.
Definition: ASTMatchersInternal.cpp:1026
clang
Dataflow Directional Tag Classes.
Definition: CalledOnceCheck.h:17
clang::AnalysisDeclContext::getDecl
const Decl * getDecl() const
Definition: AnalysisDeclContext.h:106
clang::ast_matchers::match
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
Definition: ASTMatchFinder.h:310
clang::ast_matchers::hasName
internal::Matcher< NamedDecl > hasName(StringRef Name)
Matches NamedDecl nodes that have the specified name.
Definition: ASTMatchers.h:2940
clang::ento::PathDiagnosticLocation::createBegin
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
Definition: PathDiagnostic.cpp:580
clang::ast_matchers::BoundNodes
Maps string IDs to AST nodes matched by parts of a matcher.
Definition: ASTMatchers.h:107
clang::ast_matchers::DeclarationMatcher
internal::Matcher< Decl > DeclarationMatcher
Types of matchers for the top-level classes in the AST class hierarchy.
Definition: ASTMatchers.h:141
clang::ast_matchers::cxxRecordDecl
const internal::VariadicDynCastAllOfMatcher< Decl, CXXRecordDecl > cxxRecordDecl
Matches C++ class declarations.
Definition: ASTMatchersInternal.cpp:745
AnalysisManager.h
clang::CastExpr
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition: Expr.h:3397