1 //== ObjCAtSyncChecker.cpp - nil mutex checker for @synchronized -*- C++ -*--=//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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
;
25 class ObjCAtSyncChecker
: public CheckerVisitor
<ObjCAtSyncChecker
> {
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()) {
53 BT_undef
= new BuiltinBug("Uninitialized value used as mutex "
55 EnhancedBugReport
*report
=
56 new EnhancedBugReport(*BT_undef
, BT_undef
->getDescription(), N
);
57 report
->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue
, Ex
);
66 // Check for null mutexes.
67 const GRState
*notNullState
, *nullState
;
68 llvm::tie(notNullState
, nullState
) = state
->assume(cast
<DefinedSVal
>(V
));
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
)) {
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
,
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
93 C
.addTransition(notNullState
);