blob: 41580955a9a4fade0e366a799c62f1b31f019acf [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
60 // Check for null mutexes.
61 const GRState *notNullState, *nullState;
62 llvm::tie(notNullState, nullState) = state->Assume(cast<DefinedSVal>(V));
63
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);
76
77 C.EmitReport(report);
Ted Kremenek1adee4b2010-10-21 15:38:55 +000078 return;
Ted Kremenek942e24d2010-09-10 03:45:29 +000079 }
80 }
Ted Kremenek1adee4b2010-10-21 15:38:55 +000081 // 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.
Ted Kremenek942e24d2010-09-10 03:45:29 +000084 }
85
86 if (notNullState)
87 C.addTransition(notNullState);
88}
Ted Kremenek1adee4b2010-10-21 15:38:55 +000089