Coverage Report

Created: 2017-10-03 07:32

/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//== ObjCContainersASTChecker.cpp - CoreFoundation containers API *- C++ -*-==//
2
//
3
//                     The LLVM Compiler Infrastructure
4
//
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
7
//
8
//===----------------------------------------------------------------------===//
9
//
10
// An AST checker that looks for common pitfalls when using 'CFArray',
11
// 'CFDictionary', 'CFSet' APIs.
12
//
13
//===----------------------------------------------------------------------===//
14
#include "ClangSACheckers.h"
15
#include "clang/AST/StmtVisitor.h"
16
#include "clang/Analysis/AnalysisDeclContext.h"
17
#include "clang/Basic/TargetInfo.h"
18
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
19
#include "clang/StaticAnalyzer/Core/Checker.h"
20
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
21
#include "llvm/ADT/SmallString.h"
22
#include "llvm/Support/raw_ostream.h"
23
24
using namespace clang;
25
using namespace ento;
26
27
namespace {
28
class WalkAST : public StmtVisitor<WalkAST> {
29
  BugReporter &BR;
30
  const CheckerBase *Checker;
31
  AnalysisDeclContext* AC;
32
  ASTContext &ASTC;
33
  uint64_t PtrWidth;
34
35
  /// Check if the type has pointer size (very conservative).
36
21
  inline bool isPointerSize(const Type *T) {
37
21
    if (!T)
38
0
      return true;
39
21
    
if (21
T->isIncompleteType()21
)
40
0
      return true;
41
21
    return (ASTC.getTypeSize(T) == PtrWidth);
42
21
  }
43
44
  /// Check if the type is a pointer/array to pointer sized values.
45
24
  inline bool hasPointerToPointerSizedType(const Expr *E) {
46
24
    QualType T = E->getType();
47
24
48
24
    // The type could be either a pointer or array.
49
24
    const Type *TP = T.getTypePtr();
50
24
    QualType PointeeT = TP->getPointeeType();
51
24
    if (
!PointeeT.isNull()24
) {
52
13
      // If the type is a pointer to an array, check the size of the array
53
13
      // elements. To avoid false positives coming from assumption that the
54
13
      // values x and &x are equal when x is an array.
55
13
      if (const Type *TElem = PointeeT->getArrayElementTypeNoTypeQual())
56
3
        
if (3
isPointerSize(TElem)3
)
57
2
          return true;
58
11
59
11
      // Else, check the pointee size.
60
11
      return isPointerSize(PointeeT.getTypePtr());
61
11
    }
62
11
63
11
    
if (const Type *11
TElem11
= TP->getArrayElementTypeNoTypeQual())
64
7
      return isPointerSize(TElem);
65
4
66
4
    // The type must be an array/pointer type.
67
4
68
4
    // This could be a null constant, which is allowed.
69
4
    return static_cast<bool>(
70
4
        E->isNullPointerConstant(ASTC, Expr::NPC_ValueDependentIsNull));
71
4
  }
72
73
public:
74
  WalkAST(BugReporter &br, const CheckerBase *checker, AnalysisDeclContext *ac)
75
      : BR(br), Checker(checker), AC(ac), ASTC(AC->getASTContext()),
76
58
        PtrWidth(ASTC.getTargetInfo().getPointerWidth(0)) {}
77
78
  // Statement visitor methods.
79
  void VisitChildren(Stmt *S);
80
1.20k
  void VisitStmt(Stmt *S) { VisitChildren(S); }
81
  void VisitCallExpr(CallExpr *CE);
82
};
83
} // end anonymous namespace
84
85
91
static StringRef getCalleeName(CallExpr *CE) {
86
91
  const FunctionDecl *FD = CE->getDirectCallee();
87
91
  if (!FD)
88
0
    return StringRef();
89
91
90
91
  IdentifierInfo *II = FD->getIdentifier();
91
91
  if (!II)   // if no identifier, not a simple C function
92
0
    return StringRef();
93
91
94
91
  return II->getName();
95
91
}
96
97
91
void WalkAST::VisitCallExpr(CallExpr *CE) {
98
91
  StringRef Name = getCalleeName(CE);
99
91
  if (Name.empty())
100
0
    return;
101
91
102
91
  const Expr *Arg = nullptr;
103
91
  unsigned ArgNum;
104
91
105
91
  if (
Name.equals("CFArrayCreate") || 91
Name.equals("CFSetCreate")73
) {
106
21
    if (CE->getNumArgs() != 4)
107
2
      return;
108
19
    ArgNum = 1;
109
19
    Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
110
19
    if (hasPointerToPointerSizedType(Arg))
111
14
        return;
112
70
  } else 
if (70
Name.equals("CFDictionaryCreate")70
) {
113
4
    if (CE->getNumArgs() != 6)
114
1
      return;
115
3
    // Check first argument.
116
3
    ArgNum = 1;
117
3
    Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
118
3
    if (
hasPointerToPointerSizedType(Arg)3
) {
119
2
      // Check second argument.
120
2
      ArgNum = 2;
121
2
      Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
122
2
      if (hasPointerToPointerSizedType(Arg))
123
2
        // Both are good, return.
124
1
        return;
125
73
    }
126
70
  }
127
73
128
73
  
if (73
Arg73
) {
129
7
    assert(ArgNum == 1 || ArgNum == 2);
130
7
131
7
    SmallString<64> BufName;
132
7
    llvm::raw_svector_ostream OsName(BufName);
133
7
    OsName << " Invalid use of '" << Name << "'" ;
134
7
135
7
    SmallString<256> Buf;
136
7
    llvm::raw_svector_ostream Os(Buf);
137
7
    // Use "second" and "third" since users will expect 1-based indexing
138
7
    // for parameter names when mentioned in prose.
139
7
    Os << " The "<< ((ArgNum == 1) ? 
"second"6
:
"third"1
) << " argument to '"
140
7
        << Name << "' must be a C array of pointer-sized values, not '"
141
7
        << Arg->getType().getAsString() << "'";
142
7
143
7
    PathDiagnosticLocation CELoc =
144
7
        PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
145
7
    BR.EmitBasicReport(AC->getDecl(), Checker, OsName.str(),
146
7
                       categories::CoreFoundationObjectiveC, Os.str(), CELoc,
147
7
                       Arg->getSourceRange());
148
7
  }
149
91
150
91
  // Recurse and check children.
151
91
  VisitChildren(CE);
152
91
}
153
154
1.27k
void WalkAST::VisitChildren(Stmt *S) {
155
1.27k
  for (Stmt *Child : S->children())
156
1.30k
    
if (1.30k
Child1.30k
)
157
1.23k
      Visit(Child);
158
1.27k
}
159
160
namespace {
161
class ObjCContainersASTChecker : public Checker<check::ASTCodeBody> {
162
public:
163
164
  void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
165
58
                        BugReporter &BR) const {
166
58
    WalkAST walker(BR, this, Mgr.getAnalysisDeclContext(D));
167
58
    walker.Visit(D->getBody());
168
58
  }
169
};
170
}
171
172
12
void ento::registerObjCContainersASTChecker(CheckerManager &mgr) {
173
12
  mgr.registerChecker<ObjCContainersASTChecker>();
174
12
}