Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
// MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- 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 defines MacOSXAPIChecker, which is an assortment of checks on calls
10
// to various, widely used Apple APIs.
11
//
12
// FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated
13
// to here, using the new Checker interface.
14
//
15
//===----------------------------------------------------------------------===//
16
17
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
18
#include "clang/Basic/TargetInfo.h"
19
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
20
#include "clang/StaticAnalyzer/Core/Checker.h"
21
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
22
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
23
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
24
#include "llvm/ADT/SmallString.h"
25
#include "llvm/ADT/StringSwitch.h"
26
#include "llvm/Support/raw_ostream.h"
27
28
using namespace clang;
29
using namespace ento;
30
31
namespace {
32
class MacOSXAPIChecker : public Checker< check::PreStmt<CallExpr> > {
33
  mutable std::unique_ptr<BugType> BT_dispatchOnce;
34
35
  static const ObjCIvarRegion *getParentIvarRegion(const MemRegion *R);
36
37
public:
38
  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
39
40
  void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
41
                         StringRef FName) const;
42
43
  typedef void (MacOSXAPIChecker::*SubChecker)(CheckerContext &,
44
                                               const CallExpr *,
45
                                               StringRef FName) const;
46
};
47
} //end anonymous namespace
48
49
//===----------------------------------------------------------------------===//
50
// dispatch_once and dispatch_once_f
51
//===----------------------------------------------------------------------===//
52
53
const ObjCIvarRegion *
54
24
MacOSXAPIChecker::getParentIvarRegion(const MemRegion *R) {
55
24
  const SubRegion *SR = dyn_cast<SubRegion>(R);
56
48
  while (SR) {
57
42
    if (const ObjCIvarRegion *IR = dyn_cast<ObjCIvarRegion>(SR))
58
18
      return IR;
59
24
    SR = dyn_cast<SubRegion>(SR->getSuperRegion());
60
24
  }
61
24
  
return nullptr6
;
62
24
}
63
64
void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
65
54
                                         StringRef FName) const {
66
54
  if (CE->getNumArgs() < 1)
67
0
    return;
68
54
69
54
  // Check if the first argument is improperly allocated.  If so, issue a
70
54
  // warning because that's likely to be bad news.
71
54
  const MemRegion *R = C.getSVal(CE->getArg(0)).getAsRegion();
72
54
  if (!R)
73
0
    return;
74
54
75
54
  // Global variables are fine.
76
54
  const MemRegion *RB = R->getBaseRegion();
77
54
  const MemSpaceRegion *RS = RB->getMemorySpace();
78
54
  if (isa<GlobalsSpaceRegion>(RS))
79
15
    return;
80
39
81
39
  // Handle _dispatch_once.  In some versions of the OS X SDK we have the case
82
39
  // that dispatch_once is a macro that wraps a call to _dispatch_once.
83
39
  // _dispatch_once is then a function which then calls the real dispatch_once.
84
39
  // Users do not care; they just want the warning at the top-level call.
85
39
  if (CE->getBeginLoc().isMacroID()) {
86
4
    StringRef TrimmedFName = FName.ltrim('_');
87
4
    if (TrimmedFName != FName)
88
4
      FName = TrimmedFName;
89
4
  }
90
39
91
39
  SmallString<256> S;
92
39
  llvm::raw_svector_ostream os(S);
93
39
  bool SuggestStatic = false;
94
39
  os << "Call to '" << FName << "' uses";
95
39
  if (const VarRegion *VR = dyn_cast<VarRegion>(RB)) {
96
15
    const VarDecl *VD = VR->getDecl();
97
15
    // FIXME: These should have correct memory space and thus should be filtered
98
15
    // out earlier. This branch only fires when we're looking from a block,
99
15
    // which we analyze as a top-level declaration, onto a static local
100
15
    // in a function that contains the block.
101
15
    if (VD->isStaticLocal())
102
2
      return;
103
13
    // We filtered out globals earlier, so it must be a local variable
104
13
    // or a block variable which is under UnknownSpaceRegion.
105
13
    if (VR != R)
106
2
      os << " memory within";
107
13
    if (VD->hasAttr<BlocksAttr>())
108
4
      os << " the block variable '";
109
9
    else
110
9
      os << " the local variable '";
111
13
    os << VR->getDecl()->getName() << '\'';
112
13
    SuggestStatic = true;
113
24
  } else if (const ObjCIvarRegion *IVR = getParentIvarRegion(R)) {
114
18
    if (IVR != R)
115
12
      os << " memory within";
116
18
    os << " the instance variable '" << IVR->getDecl()->getName() << '\'';
117
18
  } else 
if (6
isa<HeapSpaceRegion>(RS)6
) {
118
4
    os << " heap-allocated memory";
119
4
  } else 
if (2
isa<UnknownSpaceRegion>(RS)2
) {
120
2
    // Presence of an IVar superregion has priority over this branch, because
121
2
    // ObjC objects are on the heap even if the core doesn't realize this.
122
2
    // Presence of a block variable base region has priority over this branch,
123
2
    // because block variables are known to be either on stack or on heap
124
2
    // (might actually move between the two, hence UnknownSpace).
125
2
    return;
126
2
  } else {
127
0
    os << " stack allocated memory";
128
0
  }
129
39
  os << " for the predicate value.  Using such transient memory for "
130
35
        "the predicate is potentially dangerous.";
131
35
  if (SuggestStatic)
132
13
    os << "  Perhaps you intended to declare the variable as 'static'?";
133
35
134
35
  ExplodedNode *N = C.generateErrorNode();
135
35
  if (!N)
136
0
    return;
137
35
138
35
  if (!BT_dispatchOnce)
139
5
    BT_dispatchOnce.reset(new BugType(this, "Improper use of 'dispatch_once'",
140
5
                                      "API Misuse (Apple)"));
141
35
142
35
  auto report = llvm::make_unique<BugReport>(*BT_dispatchOnce, os.str(), N);
143
35
  report->addRange(CE->getArg(0)->getSourceRange());
144
35
  C.emitReport(std::move(report));
145
35
}
146
147
//===----------------------------------------------------------------------===//
148
// Central dispatch function.
149
//===----------------------------------------------------------------------===//
150
151
void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE,
152
452
                                    CheckerContext &C) const {
153
452
  StringRef Name = C.getCalleeName(CE);
154
452
  if (Name.empty())
155
18
    return;
156
434
157
434
  SubChecker SC =
158
434
    llvm::StringSwitch<SubChecker>(Name)
159
434
      .Cases("dispatch_once",
160
434
             "_dispatch_once",
161
434
             "dispatch_once_f",
162
434
             &MacOSXAPIChecker::CheckDispatchOnce)
163
434
      .Default(nullptr);
164
434
165
434
  if (SC)
166
54
    (this->*SC)(C, CE, Name);
167
434
}
168
169
//===----------------------------------------------------------------------===//
170
// Registration.
171
//===----------------------------------------------------------------------===//
172
173
28
void ento::registerMacOSXAPIChecker(CheckerManager &mgr) {
174
28
  mgr.registerChecker<MacOSXAPIChecker>();
175
28
}
176
177
28
bool ento::shouldRegisterMacOSXAPIChecker(const LangOptions &LO) {
178
28
  return true;
179
28
}