[analyzer] Refactoring: Move stuff into namespace 'GR'.
[clang.git] / lib / GR / Checkers / ObjCAtSyncChecker.cpp
bloba3938627b1fdb9d85cacc216c5c63b894dce292e
1 //== ObjCAtSyncChecker.cpp - nil mutex checker for @synchronized -*- 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 // This defines ObjCAtSyncChecker, a builtin check that checks for null pointers
11 // used as mutexes for @synchronized.
13 //===----------------------------------------------------------------------===//
15 #include "GRExprEngineInternalChecks.h"
16 #include "clang/GR/BugReporter/BugType.h"
17 #include "clang/GR/Checkers/DereferenceChecker.h"
18 #include "clang/GR/PathSensitive/CheckerVisitor.h"
19 #include "clang/GR/PathSensitive/GRExprEngine.h"
21 using namespace clang;
22 using namespace GR;
24 namespace {
25 class ObjCAtSyncChecker : public CheckerVisitor<ObjCAtSyncChecker> {
26 BuiltinBug *BT_null;
27 BuiltinBug *BT_undef;
28 public:
29 ObjCAtSyncChecker() : BT_null(0), BT_undef(0) {}
30 static void *getTag() { static int tag = 0; return &tag; }
31 void PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
32 const ObjCAtSynchronizedStmt *S);
34 } // end anonymous namespace
36 void GR::RegisterObjCAtSyncChecker(GRExprEngine &Eng) {
37 // @synchronized is an Objective-C 2 feature.
38 if (Eng.getContext().getLangOptions().ObjC2)
39 Eng.registerCheck(new ObjCAtSyncChecker());
42 void ObjCAtSyncChecker::PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
43 const ObjCAtSynchronizedStmt *S) {
45 const Expr *Ex = S->getSynchExpr();
46 const GRState *state = C.getState();
47 SVal V = state->getSVal(Ex);
49 // Uninitialized value used for the mutex?
50 if (isa<UndefinedVal>(V)) {
51 if (ExplodedNode *N = C.generateSink()) {
52 if (!BT_undef)
53 BT_undef = new BuiltinBug("Uninitialized value used as mutex "
54 "for @synchronized");
55 EnhancedBugReport *report =
56 new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
57 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
58 C.EmitReport(report);
60 return;
63 if (V.isUnknown())
64 return;
66 // Check for null mutexes.
67 const GRState *notNullState, *nullState;
68 llvm::tie(notNullState, nullState) = state->assume(cast<DefinedSVal>(V));
70 if (nullState) {
71 if (!notNullState) {
72 // Generate an error node. This isn't a sink since
73 // a null mutex just means no synchronization occurs.
74 if (ExplodedNode *N = C.generateNode(nullState)) {
75 if (!BT_null)
76 BT_null = new BuiltinBug("Nil value used as mutex for @synchronized() "
77 "(no synchronization will occur)");
78 EnhancedBugReport *report =
79 new EnhancedBugReport(*BT_null, BT_null->getDescription(), N);
80 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
81 Ex);
83 C.EmitReport(report);
84 return;
87 // Don't add a transition for 'nullState'. If the value is
88 // under-constrained to be null or non-null, assume it is non-null
89 // afterwards.
92 if (notNullState)
93 C.addTransition(notNullState);