clang  9.0.0
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 
28 const char *WarnAtNode = "OSObjCast";
29 
30 class OSObjectCStyleCastChecker : public Checker<check::ASTCodeBody> {
31 public:
32  void checkASTCodeBody(const Decl *D,
33  AnalysisManager &AM,
34  BugReporter &BR) const;
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  assert(CE);
43 
44  std::string Diagnostics;
45  llvm::raw_string_ostream OS(Diagnostics);
46  OS << "C-style cast of OSObject. Use OSDynamicCast instead.";
47 
48  BR.EmitBasicReport(
49  ADC->getDecl(),
50  Checker,
51  /*Name=*/"OSObject C-Style Cast",
52  /*BugCategory=*/"Security",
53  OS.str(),
54  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), ADC),
55  CE->getSourceRange());
56 }
57 
58 static auto hasTypePointingTo(DeclarationMatcher DeclM)
59  -> decltype(hasType(pointerType())) {
60  return hasType(pointerType(pointee(hasDeclaration(DeclM))));
61 }
62 
63 void OSObjectCStyleCastChecker::checkASTCodeBody(const Decl *D, AnalysisManager &AM,
64  BugReporter &BR) const {
65 
66  AnalysisDeclContext *ADC = AM.getAnalysisDeclContext(D);
67 
68  auto DynamicCastM = callExpr(callee(functionDecl(hasName("safeMetaCast"))));
69 
70  auto OSObjTypeM = hasTypePointingTo(cxxRecordDecl(isDerivedFrom("OSMetaClassBase")));
71  auto OSObjSubclassM = hasTypePointingTo(
72  cxxRecordDecl(isDerivedFrom("OSObject")));
73 
74  auto CastM = cStyleCastExpr(
75  allOf(hasSourceExpression(allOf(OSObjTypeM, unless(DynamicCastM))),
76  OSObjSubclassM)).bind(WarnAtNode);
77 
78  auto Matches = match(stmt(forEachDescendant(CastM)), *D->getBody(), AM.getASTContext());
79  for (BoundNodes Match : Matches)
80  emitDiagnostics(Match, BR, ADC, this);
81 }
82 }
83 
84 void ento::registerOSObjectCStyleCast(CheckerManager &Mgr) {
85  Mgr.registerChecker<OSObjectCStyleCastChecker>();
86 }
87 
88 bool ento::shouldRegisterOSObjectCStyleCast(const LangOptions &LO) {
89  return true;
90 }
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
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:986
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:2884
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:88
const AstTypeMatcher< PointerType > pointerType
Matches pointer types, but does not match Objective-C object pointer types.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> allOf
Matches if all given matchers match.
const internal::VariadicDynCastAllOfMatcher< Decl, FunctionDecl > functionDecl
Matches function declarations.
BoundNodesTreeBuilder Nodes
AnalysisDeclContext contains the context data for the function or method under analysis.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:49
const T * getNodeAs(StringRef ID) const
Returns the AST node bound to ID.
Definition: ASTMatchers.h:110
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition: Expr.h:3121
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
const internal::ArgumentAdaptingMatcherFunc< internal::ForEachDescendantMatcher > forEachDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher. ...
const internal::VariadicDynCastAllOfMatcher< Stmt, CStyleCastExpr > cStyleCastExpr
Matches a C-style cast expression.
Maps string IDs to AST nodes matched by parts of a matcher.
Definition: ASTMatchers.h:103
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
const Decl * getDecl() const
static void emitDiagnostics(BoundNodes &Match, const Decl *D, BugReporter &BR, AnalysisManager &AM, const ObjCAutoreleaseWriteChecker *Checker)
const internal::VariadicOperatorMatcherFunc< 1, 1 > unless
Matches if the provided matcher does not match.
Dataflow Directional Tag Classes.
const internal::VariadicDynCastAllOfMatcher< Decl, CXXRecordDecl > cxxRecordDecl
Matches C++ class declarations.
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
internal::Matcher< NamedDecl > hasName(const std::string &Name)
Matches NamedDecl nodes that have the specified name.
Definition: ASTMatchers.h:2545
internal::Matcher< Decl > DeclarationMatcher
Types of matchers for the top-level classes in the AST class hierarchy.
Definition: ASTMatchers.h:146