Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//= UnixAPIChecker.h - Checks preconditions for various Unix 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 UnixAPIChecker, which is an assortment of checks on calls
10
// to various, widely used UNIX/Posix functions.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15
#include "clang/Basic/TargetInfo.h"
16
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17
#include "clang/StaticAnalyzer/Core/Checker.h"
18
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20
#include "llvm/ADT/Optional.h"
21
#include "llvm/ADT/STLExtras.h"
22
#include "llvm/ADT/SmallString.h"
23
#include "llvm/Support/raw_ostream.h"
24
25
using namespace clang;
26
using namespace ento;
27
28
enum class OpenVariant {
29
  /// The standard open() call:
30
  ///    int open(const char *path, int oflag, ...);
31
  Open,
32
33
  /// The variant taking a directory file descriptor and a relative path:
34
  ///    int openat(int fd, const char *path, int oflag, ...);
35
  OpenAt
36
};
37
38
namespace {
39
40
class UnixAPIMisuseChecker : public Checker< check::PreStmt<CallExpr> > {
41
  mutable std::unique_ptr<BugType> BT_open, BT_pthreadOnce;
42
  mutable Optional<uint64_t> Val_O_CREAT;
43
44
public:
45
  DefaultBool CheckMisuse, CheckPortability;
46
47
  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
48
49
  void CheckOpen(CheckerContext &C, const CallExpr *CE) const;
50
  void CheckOpenAt(CheckerContext &C, const CallExpr *CE) const;
51
  void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const;
52
53
  void CheckOpenVariant(CheckerContext &C,
54
                        const CallExpr *CE, OpenVariant Variant) const;
55
56
  void ReportOpenBug(CheckerContext &C,
57
                     ProgramStateRef State,
58
                     const char *Msg,
59
                     SourceRange SR) const;
60
61
};
62
63
class UnixAPIPortabilityChecker : public Checker< check::PreStmt<CallExpr> > {
64
public:
65
  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
66
67
private:
68
  mutable std::unique_ptr<BugType> BT_mallocZero;
69
70
  void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const;
71
  void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;
72
  void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const;
73
  void CheckReallocfZero(CheckerContext &C, const CallExpr *CE) const;
74
  void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const;
75
  void CheckAllocaWithAlignZero(CheckerContext &C, const CallExpr *CE) const;
76
  void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const;
77
78
  bool ReportZeroByteAllocation(CheckerContext &C,
79
                                ProgramStateRef falseState,
80
                                const Expr *arg,
81
                                const char *fn_name) const;
82
  void BasicAllocationCheck(CheckerContext &C,
83
                            const CallExpr *CE,
84
                            const unsigned numArgs,
85
                            const unsigned sizeArg,
86
                            const char *fn) const;
87
};
88
89
} //end anonymous namespace
90
91
static void LazyInitialize(const CheckerBase *Checker,
92
                           std::unique_ptr<BugType> &BT,
93
37
                           const char *name) {
94
37
  if (BT)
95
28
    return;
96
9
  BT.reset(new BugType(Checker, name, categories::UnixAPI));
97
9
}
98
99
//===----------------------------------------------------------------------===//
100
// "open" (man 2 open)
101
//===----------------------------------------------------------------------===/
102
103
void UnixAPIMisuseChecker::checkPreStmt(const CallExpr *CE,
104
270
                                        CheckerContext &C) const {
105
270
  const FunctionDecl *FD = C.getCalleeDecl(CE);
106
270
  if (!FD || 
FD->getKind() != Decl::Function259
)
107
23
    return;
108
247
109
247
  // Don't treat functions in namespaces with the same name a Unix function
110
247
  // as a call to the Unix function.
111
247
  const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext();
112
247
  if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx))
113
2
    return;
114
245
115
245
  StringRef FName = C.getCalleeName(FD);
116
245
  if (FName.empty())
117
0
    return;
118
245
119
245
  if (FName == "open")
120
17
    CheckOpen(C, CE);
121
228
122
228
  else if (FName == "openat")
123
8
    CheckOpenAt(C, CE);
124
220
125
220
  else if (FName == "pthread_once")
126
4
    CheckPthreadOnce(C, CE);
127
245
}
128
void UnixAPIMisuseChecker::ReportOpenBug(CheckerContext &C,
129
                                         ProgramStateRef State,
130
                                         const char *Msg,
131
18
                                         SourceRange SR) const {
132
18
  ExplodedNode *N = C.generateErrorNode(State);
133
18
  if (!N)
134
0
    return;
135
18
136
18
  LazyInitialize(this, BT_open, "Improper use of 'open'");
137
18
138
18
  auto Report = llvm::make_unique<BugReport>(*BT_open, Msg, N);
139
18
  Report->addRange(SR);
140
18
  C.emitReport(std::move(Report));
141
18
}
142
143
void UnixAPIMisuseChecker::CheckOpen(CheckerContext &C,
144
17
                                     const CallExpr *CE) const {
145
17
  CheckOpenVariant(C, CE, OpenVariant::Open);
146
17
}
147
148
void UnixAPIMisuseChecker::CheckOpenAt(CheckerContext &C,
149
8
                                       const CallExpr *CE) const {
150
8
  CheckOpenVariant(C, CE, OpenVariant::OpenAt);
151
8
}
152
153
void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C,
154
                                            const CallExpr *CE,
155
25
                                            OpenVariant Variant) const {
156
25
  // The index of the argument taking the flags open flags (O_RDONLY,
157
25
  // O_WRONLY, O_CREAT, etc.),
158
25
  unsigned int FlagsArgIndex;
159
25
  const char *VariantName;
160
25
  switch (Variant) {
161
25
  case OpenVariant::Open:
162
17
    FlagsArgIndex = 1;
163
17
    VariantName = "open";
164
17
    break;
165
25
  case OpenVariant::OpenAt:
166
8
    FlagsArgIndex = 2;
167
8
    VariantName = "openat";
168
8
    break;
169
25
  };
170
25
171
25
  // All calls should at least provide arguments up to the 'flags' parameter.
172
25
  unsigned int MinArgCount = FlagsArgIndex + 1;
173
25
174
25
  // If the flags has O_CREAT set then open/openat() require an additional
175
25
  // argument specifying the file mode (permission bits) for the created file.
176
25
  unsigned int CreateModeArgIndex = FlagsArgIndex + 1;
177
25
178
25
  // The create mode argument should be the last argument.
179
25
  unsigned int MaxArgCount = CreateModeArgIndex + 1;
180
25
181
25
  ProgramStateRef state = C.getState();
182
25
183
25
  if (CE->getNumArgs() < MinArgCount) {
184
0
    // The frontend should issue a warning for this case, so this is a sanity
185
0
    // check.
186
0
    return;
187
25
  } else if (CE->getNumArgs() == MaxArgCount) {
188
7
    const Expr *Arg = CE->getArg(CreateModeArgIndex);
189
7
    QualType QT = Arg->getType();
190
7
    if (!QT->isIntegerType()) {
191
6
      SmallString<256> SBuf;
192
6
      llvm::raw_svector_ostream OS(SBuf);
193
6
      OS << "The " << CreateModeArgIndex + 1
194
6
         << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
195
6
         << " argument to '" << VariantName << "' is not an integer";
196
6
197
6
      ReportOpenBug(C, state,
198
6
                    SBuf.c_str(),
199
6
                    Arg->getSourceRange());
200
6
      return;
201
6
    }
202
18
  } else if (CE->getNumArgs() > MaxArgCount) {
203
4
    SmallString<256> SBuf;
204
4
    llvm::raw_svector_ostream OS(SBuf);
205
4
    OS << "Call to '" << VariantName << "' with more than " << MaxArgCount
206
4
       << " arguments";
207
4
208
4
    ReportOpenBug(C, state,
209
4
                  SBuf.c_str(),
210
4
                  CE->getArg(MaxArgCount)->getSourceRange());
211
4
    return;
212
4
  }
213
15
214
15
  // The definition of O_CREAT is platform specific.  We need a better way
215
15
  // of querying this information from the checking environment.
216
15
  if (!Val_O_CREAT.hasValue()) {
217
4
    if (C.getASTContext().getTargetInfo().getTriple().getVendor()
218
4
                                                      == llvm::Triple::Apple)
219
4
      Val_O_CREAT = 0x0200;
220
0
    else {
221
0
      // FIXME: We need a more general way of getting the O_CREAT value.
222
0
      // We could possibly grovel through the preprocessor state, but
223
0
      // that would require passing the Preprocessor object to the ExprEngine.
224
0
      // See also: MallocChecker.cpp / M_ZERO.
225
0
      return;
226
0
    }
227
15
  }
228
15
229
15
  // Now check if oflags has O_CREAT set.
230
15
  const Expr *oflagsEx = CE->getArg(FlagsArgIndex);
231
15
  const SVal V = C.getSVal(oflagsEx);
232
15
  if (!V.getAs<NonLoc>()) {
233
0
    // The case where 'V' can be a location can only be due to a bad header,
234
0
    // so in this case bail out.
235
0
    return;
236
0
  }
237
15
  NonLoc oflags = V.castAs<NonLoc>();
238
15
  NonLoc ocreateFlag = C.getSValBuilder()
239
15
      .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->getType()).castAs<NonLoc>();
240
15
  SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
241
15
                                                      oflags, ocreateFlag,
242
15
                                                      oflagsEx->getType());
243
15
  if (maskedFlagsUC.isUnknownOrUndef())
244
0
    return;
245
15
  DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>();
246
15
247
15
  // Check if maskedFlags is non-zero.
248
15
  ProgramStateRef trueState, falseState;
249
15
  std::tie(trueState, falseState) = state->assume(maskedFlags);
250
15
251
15
  // Only emit an error if the value of 'maskedFlags' is properly
252
15
  // constrained;
253
15
  if (!(trueState && 
!falseState8
))
254
7
    return;
255
8
256
8
  if (CE->getNumArgs() < MaxArgCount) {
257
8
    SmallString<256> SBuf;
258
8
    llvm::raw_svector_ostream OS(SBuf);
259
8
    OS << "Call to '" << VariantName << "' requires a "
260
8
       << CreateModeArgIndex + 1
261
8
       << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
262
8
       << " argument when the 'O_CREAT' flag is set";
263
8
    ReportOpenBug(C, trueState,
264
8
                  SBuf.c_str(),
265
8
                  oflagsEx->getSourceRange());
266
8
  }
267
8
}
268
269
//===----------------------------------------------------------------------===//
270
// pthread_once
271
//===----------------------------------------------------------------------===//
272
273
void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
274
4
                                      const CallExpr *CE) const {
275
4
276
4
  // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.
277
4
  // They can possibly be refactored.
278
4
279
4
  if (CE->getNumArgs() < 1)
280
0
    return;
281
4
282
4
  // Check if the first argument is stack allocated.  If so, issue a warning
283
4
  // because that's likely to be bad news.
284
4
  ProgramStateRef state = C.getState();
285
4
  const MemRegion *R = C.getSVal(CE->getArg(0)).getAsRegion();
286
4
  if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
287
2
    return;
288
2
289
2
  ExplodedNode *N = C.generateErrorNode(state);
290
2
  if (!N)
291
0
    return;
292
2
293
2
  SmallString<256> S;
294
2
  llvm::raw_svector_ostream os(S);
295
2
  os << "Call to 'pthread_once' uses";
296
2
  if (const VarRegion *VR = dyn_cast<VarRegion>(R))
297
2
    os << " the local variable '" << VR->getDecl()->getName() << '\'';
298
0
  else
299
0
    os << " stack allocated memory";
300
2
  os << " for the \"control\" value.  Using such transient memory for "
301
2
  "the control value is potentially dangerous.";
302
2
  if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
303
2
    os << "  Perhaps you intended to declare the variable as 'static'?";
304
2
305
2
  LazyInitialize(this, BT_pthreadOnce, "Improper use of 'pthread_once'");
306
2
307
2
  auto report = llvm::make_unique<BugReport>(*BT_pthreadOnce, os.str(), N);
308
2
  report->addRange(CE->getArg(0)->getSourceRange());
309
2
  C.emitReport(std::move(report));
310
2
}
311
312
//===----------------------------------------------------------------------===//
313
// "calloc", "malloc", "realloc", "reallocf", "alloca" and "valloc"
314
// with allocation size 0
315
//===----------------------------------------------------------------------===//
316
317
// FIXME: Eventually these should be rolled into the MallocChecker, but right now
318
// they're more basic and valuable for widespread use.
319
320
// Returns true if we try to do a zero byte allocation, false otherwise.
321
// Fills in trueState and falseState.
322
static bool IsZeroByteAllocation(ProgramStateRef state,
323
                                 const SVal argVal,
324
                                 ProgramStateRef *trueState,
325
38
                                 ProgramStateRef *falseState) {
326
38
  std::tie(*trueState, *falseState) =
327
38
    state->assume(argVal.castAs<DefinedSVal>());
328
38
329
38
  return (*falseState && 
!*trueState34
);
330
38
}
331
332
// Generates an error report, indicating that the function whose name is given
333
// will perform a zero byte allocation.
334
// Returns false if an error occurred, true otherwise.
335
bool UnixAPIPortabilityChecker::ReportZeroByteAllocation(
336
                                                    CheckerContext &C,
337
                                                    ProgramStateRef falseState,
338
                                                    const Expr *arg,
339
17
                                                    const char *fn_name) const {
340
17
  ExplodedNode *N = C.generateErrorNode(falseState);
341
17
  if (!N)
342
0
    return false;
343
17
344
17
  LazyInitialize(this, BT_mallocZero,
345
17
                 "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
346
17
347
17
  SmallString<256> S;
348
17
  llvm::raw_svector_ostream os(S);
349
17
  os << "Call to '" << fn_name << "' has an allocation size of 0 bytes";
350
17
  auto report = llvm::make_unique<BugReport>(*BT_mallocZero, os.str(), N);
351
17
352
17
  report->addRange(arg->getSourceRange());
353
17
  bugreporter::trackExpressionValue(N, arg, *report);
354
17
  C.emitReport(std::move(report));
355
17
356
17
  return true;
357
17
}
358
359
// Does a basic check for 0-sized allocations suitable for most of the below
360
// functions (modulo "calloc")
361
void UnixAPIPortabilityChecker::BasicAllocationCheck(CheckerContext &C,
362
                                                     const CallExpr *CE,
363
                                                     const unsigned numArgs,
364
                                                     const unsigned sizeArg,
365
28
                                                     const char *fn) const {
366
28
  // Sanity check for the correct number of arguments
367
28
  if (CE->getNumArgs() != numArgs)
368
0
    return;
369
28
370
28
  // Check if the allocation size is 0.
371
28
  ProgramStateRef state = C.getState();
372
28
  ProgramStateRef trueState = nullptr, falseState = nullptr;
373
28
  const Expr *arg = CE->getArg(sizeArg);
374
28
  SVal argVal = C.getSVal(arg);
375
28
376
28
  if (argVal.isUnknownOrUndef())
377
0
    return;
378
28
379
28
  // Is the value perfectly constrained to zero?
380
28
  if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
381
13
    (void) ReportZeroByteAllocation(C, falseState, arg, fn);
382
13
    return;
383
13
  }
384
15
  // Assume the value is non-zero going forward.
385
15
  assert(trueState);
386
15
  if (trueState != state)
387
13
    C.addTransition(trueState);
388
15
}
389
390
void UnixAPIPortabilityChecker::CheckCallocZero(CheckerContext &C,
391
6
                                                const CallExpr *CE) const {
392
6
  unsigned int nArgs = CE->getNumArgs();
393
6
  if (nArgs != 2)
394
0
    return;
395
6
396
6
  ProgramStateRef state = C.getState();
397
6
  ProgramStateRef trueState = nullptr, falseState = nullptr;
398
6
399
6
  unsigned int i;
400
12
  for (i = 0; i < nArgs; 
i++6
) {
401
10
    const Expr *arg = CE->getArg(i);
402
10
    SVal argVal = C.getSVal(arg);
403
10
    if (argVal.isUnknownOrUndef()) {
404
0
      if (i == 0)
405
0
        continue;
406
0
      else
407
0
        return;
408
10
    }
409
10
410
10
    if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
411
4
      if (ReportZeroByteAllocation(C, falseState, arg, "calloc"))
412
4
        return;
413
0
      else if (i == 0)
414
0
        continue;
415
0
      else
416
0
        return;
417
4
    }
418
10
  }
419
6
420
6
  // Assume the value is non-zero going forward.
421
6
  assert(trueState);
422
2
  if (trueState != state)
423
2
    C.addTransition(trueState);
424
2
}
425
426
void UnixAPIPortabilityChecker::CheckMallocZero(CheckerContext &C,
427
8
                                                const CallExpr *CE) const {
428
8
  BasicAllocationCheck(C, CE, 1, 0, "malloc");
429
8
}
430
431
void UnixAPIPortabilityChecker::CheckReallocZero(CheckerContext &C,
432
4
                                                 const CallExpr *CE) const {
433
4
  BasicAllocationCheck(C, CE, 2, 1, "realloc");
434
4
}
435
436
void UnixAPIPortabilityChecker::CheckReallocfZero(CheckerContext &C,
437
4
                                                  const CallExpr *CE) const {
438
4
  BasicAllocationCheck(C, CE, 2, 1, "reallocf");
439
4
}
440
441
void UnixAPIPortabilityChecker::CheckAllocaZero(CheckerContext &C,
442
8
                                                const CallExpr *CE) const {
443
8
  BasicAllocationCheck(C, CE, 1, 0, "alloca");
444
8
}
445
446
void UnixAPIPortabilityChecker::CheckAllocaWithAlignZero(
447
                                                     CheckerContext &C,
448
0
                                                     const CallExpr *CE) const {
449
0
  BasicAllocationCheck(C, CE, 2, 0, "__builtin_alloca_with_align");
450
0
}
451
452
void UnixAPIPortabilityChecker::CheckVallocZero(CheckerContext &C,
453
4
                                                const CallExpr *CE) const {
454
4
  BasicAllocationCheck(C, CE, 1, 0, "valloc");
455
4
}
456
457
void UnixAPIPortabilityChecker::checkPreStmt(const CallExpr *CE,
458
95
                                             CheckerContext &C) const {
459
95
  const FunctionDecl *FD = C.getCalleeDecl(CE);
460
95
  if (!FD || 
FD->getKind() != Decl::Function87
)
461
8
    return;
462
87
463
87
  // Don't treat functions in namespaces with the same name a Unix function
464
87
  // as a call to the Unix function.
465
87
  const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext();
466
87
  if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx))
467
0
    return;
468
87
469
87
  StringRef FName = C.getCalleeName(FD);
470
87
  if (FName.empty())
471
0
    return;
472
87
473
87
  if (FName == "calloc")
474
6
    CheckCallocZero(C, CE);
475
81
476
81
  else if (FName == "malloc")
477
8
    CheckMallocZero(C, CE);
478
73
479
73
  else if (FName == "realloc")
480
4
    CheckReallocZero(C, CE);
481
69
482
69
  else if (FName == "reallocf")
483
4
    CheckReallocfZero(C, CE);
484
65
485
65
  else if (FName == "alloca" || 
FName == "__builtin_alloca"61
)
486
8
    CheckAllocaZero(C, CE);
487
57
488
57
  else if (FName == "__builtin_alloca_with_align")
489
0
    CheckAllocaWithAlignZero(C, CE);
490
57
491
57
  else if (FName == "valloc")
492
4
    CheckVallocZero(C, CE);
493
87
}
494
495
//===----------------------------------------------------------------------===//
496
// Registration.
497
//===----------------------------------------------------------------------===//
498
499
#define REGISTER_CHECKER(CHECKERNAME)                                          \
500
33
  void ento::register##CHECKERNAME(CheckerManager &mgr) {                      \
501
33
    mgr.registerChecker<CHECKERNAME>();                                        \
502
33
  }                                                                            \
clang::ento::registerUnixAPIMisuseChecker(clang::ento::CheckerManager&)
Line
Count
Source
500
30
  void ento::register##CHECKERNAME(CheckerManager &mgr) {                      \
501
30
    mgr.registerChecker<CHECKERNAME>();                                        \
502
30
  }                                                                            \
clang::ento::registerUnixAPIPortabilityChecker(clang::ento::CheckerManager&)
Line
Count
Source
500
3
  void ento::register##CHECKERNAME(CheckerManager &mgr) {                      \
501
3
    mgr.registerChecker<CHECKERNAME>();                                        \
502
3
  }                                                                            \
503
                                                                               \
504
33
  bool ento::shouldRegister##CHECKERNAME(const LangOptions &LO) {              \
505
33
    return true;                                                               \
506
33
  }
clang::ento::shouldRegisterUnixAPIMisuseChecker(clang::LangOptions const&)
Line
Count
Source
504
30
  bool ento::shouldRegister##CHECKERNAME(const LangOptions &LO) {              \
505
30
    return true;                                                               \
506
30
  }
clang::ento::shouldRegisterUnixAPIPortabilityChecker(clang::LangOptions const&)
Line
Count
Source
504
3
  bool ento::shouldRegister##CHECKERNAME(const LangOptions &LO) {              \
505
3
    return true;                                                               \
506
3
  }
507
508
REGISTER_CHECKER(UnixAPIMisuseChecker)
509
REGISTER_CHECKER(UnixAPIPortabilityChecker)