blob: f9a3686c01788da8798b32891e9cab964eef09c4 [file] [log] [blame]
Ted Kremenek942e24d2010-09-10 03:45:29 +00001//== 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.
12//
13//===----------------------------------------------------------------------===//
14
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"
20
21using namespace clang;
22
23namespace {
24class ObjCAtSyncChecker : public CheckerVisitor<ObjCAtSyncChecker> {
25 BuiltinBug *BT_null;
26 BuiltinBug *BT_undef;
27public:
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);
32};
33} // end anonymous namespace
34
35void clang::RegisterObjCAtSyncChecker(GRExprEngine &Eng) {
36 Eng.registerCheck(new ObjCAtSyncChecker());
37}
38
39void ObjCAtSyncChecker::PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
40 const ObjCAtSynchronizedStmt *S) {
41
42 const Expr *Ex = S->getSynchExpr();
43 const GRState *state = C.getState();
44 SVal V = state->getSVal(Ex);
45
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);
56 }
57 return;
58 }
59
Ted Kremenek0d4f7672010-10-25 20:20:56 +000060 if (V.isUnknown())
61 return;
62
Ted Kremenek942e24d2010-09-10 03:45:29 +000063 // Check for null mutexes.
64 const GRState *notNullState, *nullState;
65 llvm::tie(notNullState, nullState) = state->Assume(cast<DefinedSVal>(V));
66
67 if (nullState) {
68 if (!notNullState) {
69 // Generate an error node. This isn't a sink since
70 // a null mutex just means no synchronization occurs.
71 if (ExplodedNode *N = C.GenerateNode(nullState)) {
72 if (!BT_null)
73 BT_null = new BuiltinBug("Nil value used as mutex for @synchronized() "
74 "(no synchronization will occur)");
75 EnhancedBugReport *report =
76 new EnhancedBugReport(*BT_null, BT_null->getDescription(), N);
77 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
78 Ex);
79
80 C.EmitReport(report);
Ted Kremenek1adee4b2010-10-21 15:38:55 +000081 return;
Ted Kremenek942e24d2010-09-10 03:45:29 +000082 }
83 }
Ted Kremenek1adee4b2010-10-21 15:38:55 +000084 // Don't add a transition for 'nullState'. If the value is
85 // under-constrained to be null or non-null, assume it is non-null
86 // afterwards.
Ted Kremenek942e24d2010-09-10 03:45:29 +000087 }
88
89 if (notNullState)
90 C.addTransition(notNullState);
91}
Ted Kremenek1adee4b2010-10-21 15:38:55 +000092