clang  14.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 } // namespace
36 
37 namespace clang {
38 namespace ast_matchers {
39 AST_MATCHER_P(StringLiteral, mentionsBoundType, std::string, BindingID) {
40  return Builder->removeBindings([this, &Node](const BoundNodesMap &Nodes) {
41  const auto &BN = Nodes.getNode(this->BindingID);
42  if (const auto *ND = BN.get<NamedDecl>()) {
43  return ND->getName() != Node.getString();
44  }
45  return true;
46  });
47 }
48 } // end namespace ast_matchers
49 } // end namespace clang
50 
51 static void emitDiagnostics(const BoundNodes &Nodes,
52  BugReporter &BR,
54  const OSObjectCStyleCastChecker *Checker) {
55  const auto *CE = Nodes.getNodeAs<CastExpr>(WarnAtNode);
56  const CXXRecordDecl *RD = Nodes.getNodeAs<CXXRecordDecl>(WarnRecordDecl);
57  assert(CE && RD);
58 
59  std::string Diagnostics;
60  llvm::raw_string_ostream OS(Diagnostics);
61  OS << "C-style cast of an OSObject is prone to type confusion attacks; "
62  << "use 'OSRequiredCast' if the object is definitely of type '"
63  << RD->getNameAsString() << "', or 'OSDynamicCast' followed by "
64  << "a null check if unsure",
65 
66  BR.EmitBasicReport(
67  ADC->getDecl(),
68  Checker,
69  /*Name=*/"OSObject C-Style Cast",
71  OS.str(),
72  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), ADC),
73  CE->getSourceRange());
74 }
75 
76 static decltype(auto) hasTypePointingTo(DeclarationMatcher DeclM) {
77  return hasType(pointerType(pointee(hasDeclaration(DeclM))));
78 }
79 
80 void OSObjectCStyleCastChecker::checkASTCodeBody(const Decl *D,
81  AnalysisManager &AM,
82  BugReporter &BR) const {
83 
84  AnalysisDeclContext *ADC = AM.getAnalysisDeclContext(D);
85 
86  auto DynamicCastM = callExpr(callee(functionDecl(hasName("safeMetaCast"))));
87  // 'allocClassWithName' allocates an object with the given type.
88  // The type is actually provided as a string argument (type's name).
89  // This makes the following pattern possible:
90  //
91  // Foo *object = (Foo *)allocClassWithName("Foo");
92  //
93  // While OSRequiredCast can be used here, it is still not a useful warning.
94  auto AllocClassWithNameM = callExpr(
95  callee(functionDecl(hasName("allocClassWithName"))),
96  // Here we want to make sure that the string argument matches the
97  // type in the cast expression.
98  hasArgument(0, stringLiteral(mentionsBoundType(WarnRecordDecl))));
99 
100  auto OSObjTypeM =
101  hasTypePointingTo(cxxRecordDecl(isDerivedFrom("OSMetaClassBase")));
102  auto OSObjSubclassM = hasTypePointingTo(
103  cxxRecordDecl(isDerivedFrom("OSObject")).bind(WarnRecordDecl));
104 
105  auto CastM =
107  allOf(OSObjSubclassM,
108  hasSourceExpression(
109  allOf(OSObjTypeM,
110  unless(anyOf(DynamicCastM, AllocClassWithNameM))))))
111  .bind(WarnAtNode);
112 
113  auto Matches =
114  match(stmt(forEachDescendant(CastM)), *D->getBody(), AM.getASTContext());
115  for (BoundNodes Match : Matches)
116  emitDiagnostics(Match, BR, ADC, this);
117 }
118 
119 void ento::registerOSObjectCStyleCast(CheckerManager &Mgr) {
120  Mgr.registerChecker<OSObjectCStyleCastChecker>();
121 }
122 
123 bool ento::shouldRegisterOSObjectCStyleCast(const CheckerManager &mgr) {
124  return true;
125 }
Nodes
BoundNodesTreeBuilder Nodes
Definition: ASTMatchFinder.cpp:82
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
clang::ast_matchers::stmt
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
Definition: ASTMatchersInternal.cpp:809
clang::ast_matchers::stringLiteral
const internal::VariadicDynCastAllOfMatcher< Stmt, StringLiteral > stringLiteral
Matches string literals (also matches wide string literals).
Definition: ASTMatchersInternal.cpp:918
clang::ast_matchers::anyOf
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf
Matches if any of the given matchers matches.
Definition: ASTMatchersInternal.cpp:988
clang::NamedDecl
This represents a decl that may have a name.
Definition: Decl.h:249
AST_MATCHER_P
#define AST_MATCHER_P(Type, DefineMatcher, ParamType, Param)
AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) { ...
Definition: ASTMatchersMacros.h:128
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:76
clang::ast_matchers::allOf
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> allOf
Matches if all given matchers match.
Definition: ASTMatchersInternal.cpp:991
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:1013
emitDiagnostics
static void emitDiagnostics(const BoundNodes &Nodes, BugReporter &BR, AnalysisDeclContext *ADC, const OSObjectCStyleCastChecker *Checker)
Definition: OSObjectCStyleCast.cpp:51
BuiltinCheckerRegistration.h
clang::ento::categories::SecurityError
const char *const SecurityError
Definition: CommonBugCategories.cpp:24
Node
DynTypedNode Node
Definition: ASTMatchFinder.cpp:67
BugReporter.h
clang::StringLiteral
StringLiteral - This represents a string literal expression, e.g.
Definition: Expr.h:1761
clang::ast_matchers::unless
const internal::VariadicOperatorMatcherFunc< 1, 1 > unless
Matches if the provided matcher does not match.
Definition: ASTMatchersInternal.cpp:1024
clang::ast_matchers::cStyleCastExpr
const internal::VariadicDynCastAllOfMatcher< Stmt, CStyleCastExpr > cStyleCastExpr
Matches a C-style cast expression.
Definition: ASTMatchersInternal.cpp:969
clang::CXXRecordDecl
Represents a C++ struct/union/class.
Definition: DeclCXX.h:255
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:816
clang::ast_matchers::functionDecl
const internal::VariadicDynCastAllOfMatcher< Decl, FunctionDecl > functionDecl
Matches function declarations.
Definition: ASTMatchersInternal.cpp:805
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:1049
clang
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:312
clang::ast_matchers::hasName
internal::Matcher< NamedDecl > hasName(StringRef Name)
Matches NamedDecl nodes that have the specified name.
Definition: ASTMatchers.h:2989
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
clang::ast_matchers::hasDeclaration
internal::PolymorphicMatcher< internal::HasDeclarationMatcher, void(internal::HasDeclarationSupportedTypes), internal::Matcher< Decl > > hasDeclaration(const internal::Matcher< Decl > &InnerMatcher)
Matches a node if the declaration associated with that node matches the given matcher.
Definition: ASTMatchers.h:3563
AnalysisManager.h
clang::CastExpr
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition: Expr.h:3473