Add checker implementation for my previous commit!
[clang.git] / lib / Checker / ObjCAtSyncChecker.cpp
blobdc2e664e0549b9b5678244881506b0e9b596af50
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/Checker/BugReporter/BugType.h"
17 #include "clang/Checker/Checkers/DereferenceChecker.h"
18 #include "clang/Checker/PathSensitive/CheckerVisitor.h"
19 #include "clang/Checker/PathSensitive/GRExprEngine.h"
21 using namespace clang;
23 namespace {
24 class ObjCAtSyncChecker : public CheckerVisitor<ObjCAtSyncChecker> {
25 BuiltinBug *BT_null;
26 BuiltinBug *BT_undef;
27 public:
28 ObjCAtSyncChecker() : BT_null(0), BT_undef(0) {}
29 static void *getTag() { static int tag = 0; return &tag; }
30 void PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
31 const ObjCAtSynchronizedStmt *S);
33 } // end anonymous namespace
35 void clang::RegisterObjCAtSyncChecker(GRExprEngine &Eng) {
36 Eng.registerCheck(new ObjCAtSyncChecker());
39 void ObjCAtSyncChecker::PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
40 const ObjCAtSynchronizedStmt *S) {
42 const Expr *Ex = S->getSynchExpr();
43 const GRState *state = C.getState();
44 SVal V = state->getSVal(Ex);
46 // Uninitialized value used for the mutex?
47 if (isa<UndefinedVal>(V)) {
48 if (ExplodedNode *N = C.GenerateSink()) {
49 if (!BT_undef)
50 BT_undef = new BuiltinBug("Uninitialized value used as mutex "
51 "for @synchronized");
52 EnhancedBugReport *report =
53 new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
54 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
55 C.EmitReport(report);
57 return;
60 // Check for null mutexes.
61 const GRState *notNullState, *nullState;
62 llvm::tie(notNullState, nullState) = state->Assume(cast<DefinedSVal>(V));
64 if (nullState) {
65 if (!notNullState) {
66 // Generate an error node. This isn't a sink since
67 // a null mutex just means no synchronization occurs.
68 if (ExplodedNode *N = C.GenerateNode(nullState)) {
69 if (!BT_null)
70 BT_null = new BuiltinBug("Nil value used as mutex for @synchronized() "
71 "(no synchronization will occur)");
72 EnhancedBugReport *report =
73 new EnhancedBugReport(*BT_null, BT_null->getDescription(), N);
74 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
75 Ex);
77 C.EmitReport(report);
80 // From this point forward, we know that the mutex is null.
81 C.addTransition(nullState);
84 if (notNullState)
85 C.addTransition(notNullState);