blob: 139cac24862e87587f4adfcec74d61ec31d3c970 [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) {
Ted Kremenek67e40d42010-11-08 16:52:54 +000036 // @synchronized is an Objective-C 2 feature.
37 if (Eng.getContext().getLangOptions().ObjC2)
38 Eng.registerCheck(new ObjCAtSyncChecker());
Ted Kremenek942e24d2010-09-10 03:45:29 +000039}
40
41void ObjCAtSyncChecker::PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
42 const ObjCAtSynchronizedStmt *S) {
43
44 const Expr *Ex = S->getSynchExpr();
45 const GRState *state = C.getState();
46 SVal V = state->getSVal(Ex);
47
48 // Uninitialized value used for the mutex?
49 if (isa<UndefinedVal>(V)) {
50 if (ExplodedNode *N = C.GenerateSink()) {
51 if (!BT_undef)
52 BT_undef = new BuiltinBug("Uninitialized value used as mutex "
53 "for @synchronized");
54 EnhancedBugReport *report =
55 new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
56 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
57 C.EmitReport(report);
58 }
59 return;
60 }
61
Ted Kremenek0d4f7672010-10-25 20:20:56 +000062 if (V.isUnknown())
63 return;
64
Ted Kremenek942e24d2010-09-10 03:45:29 +000065 // Check for null mutexes.
66 const GRState *notNullState, *nullState;
67 llvm::tie(notNullState, nullState) = state->Assume(cast<DefinedSVal>(V));
68
69 if (nullState) {
70 if (!notNullState) {
71 // Generate an error node. This isn't a sink since
72 // a null mutex just means no synchronization occurs.
73 if (ExplodedNode *N = C.GenerateNode(nullState)) {
74 if (!BT_null)
75 BT_null = new BuiltinBug("Nil value used as mutex for @synchronized() "
76 "(no synchronization will occur)");
77 EnhancedBugReport *report =
78 new EnhancedBugReport(*BT_null, BT_null->getDescription(), N);
79 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
80 Ex);
81
82 C.EmitReport(report);
Ted Kremenek1adee4b2010-10-21 15:38:55 +000083 return;
Ted Kremenek942e24d2010-09-10 03:45:29 +000084 }
85 }
Ted Kremenek1adee4b2010-10-21 15:38:55 +000086 // Don't add a transition for 'nullState'. If the value is
87 // under-constrained to be null or non-null, assume it is non-null
88 // afterwards.
Ted Kremenek942e24d2010-09-10 03:45:29 +000089 }
90
91 if (notNullState)
92 C.addTransition(notNullState);
93}
Ted Kremenek1adee4b2010-10-21 15:38:55 +000094