Coverage Report

Created: 2023-11-11 10:31

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//== ObjCAtSyncChecker.cpp - nil mutex checker for @synchronized -*- 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 ObjCAtSyncChecker, a builtin check that checks for null pointers
10
// used as mutexes for @synchronized.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15
#include "clang/AST/StmtObjC.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 "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
21
22
using namespace clang;
23
using namespace ento;
24
25
namespace {
26
class ObjCAtSyncChecker
27
    : public Checker< check::PreStmt<ObjCAtSynchronizedStmt> > {
28
  mutable std::unique_ptr<BugType> BT_null;
29
  mutable std::unique_ptr<BugType> BT_undef;
30
31
public:
32
  void checkPreStmt(const ObjCAtSynchronizedStmt *S, CheckerContext &C) const;
33
};
34
} // end anonymous namespace
35
36
void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
37
14
                                     CheckerContext &C) const {
38
39
14
  const Expr *Ex = S->getSynchExpr();
40
14
  ProgramStateRef state = C.getState();
41
14
  SVal V = C.getSVal(Ex);
42
43
  // Uninitialized value used for the mutex?
44
14
  if (isa<UndefinedVal>(V)) {
45
2
    if (ExplodedNode *N = C.generateErrorNode()) {
46
2
      if (!BT_undef)
47
2
        BT_undef.reset(new BugType(this, "Uninitialized value used as mutex "
48
2
                                         "for @synchronized"));
49
2
      auto report = std::make_unique<PathSensitiveBugReport>(
50
2
          *BT_undef, BT_undef->getDescription(), N);
51
2
      bugreporter::trackExpressionValue(N, Ex, *report);
52
2
      C.emitReport(std::move(report));
53
2
    }
54
2
    return;
55
2
  }
56
57
12
  if (V.isUnknown())
58
0
    return;
59
60
  // Check for null mutexes.
61
12
  ProgramStateRef notNullState, nullState;
62
12
  std::tie(notNullState, nullState) = state->assume(V.castAs<DefinedSVal>());
63
64
12
  if (nullState) {
65
10
    if (!notNullState) {
66
      // Generate an error node.  This isn't a sink since
67
      // a null mutex just means no synchronization occurs.
68
4
      if (ExplodedNode *N = C.generateNonFatalErrorNode(nullState)) {
69
4
        if (!BT_null)
70
2
          BT_null.reset(
71
2
              new BugType(this, "Nil value used as mutex for @synchronized() "
72
2
                                "(no synchronization will occur)"));
73
4
        auto report = std::make_unique<PathSensitiveBugReport>(
74
4
            *BT_null, BT_null->getDescription(), N);
75
4
        bugreporter::trackExpressionValue(N, Ex, *report);
76
77
4
        C.emitReport(std::move(report));
78
4
        return;
79
4
      }
80
4
    }
81
    // Don't add a transition for 'nullState'.  If the value is
82
    // under-constrained to be null or non-null, assume it is non-null
83
    // afterwards.
84
10
  }
85
86
8
  if (notNullState)
87
8
    C.addTransition(notNullState);
88
8
}
89
90
11
void ento::registerObjCAtSyncChecker(CheckerManager &mgr) {
91
11
  mgr.registerChecker<ObjCAtSyncChecker>();
92
11
}
93
94
98
bool ento::shouldRegisterObjCAtSyncChecker(const CheckerManager &mgr) {
95
98
  const LangOptions &LO = mgr.getLangOpts();
96
98
  return LO.ObjC;
97
98
}