ObjCAtSyncChecker.cpp revision 04291a7c76e16a2dc5433c80c3d13c826bf372dc
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. 12// 13//===----------------------------------------------------------------------===// 14 15#include "InternalChecks.h" 16#include "clang/StaticAnalyzer/BugReporter/BugType.h" 17#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h" 18#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h" 19#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h" 20 21using namespace clang; 22using namespace ento; 23 24namespace { 25class ObjCAtSyncChecker : public CheckerVisitor<ObjCAtSyncChecker> { 26 BuiltinBug *BT_null; 27 BuiltinBug *BT_undef; 28public: 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); 33}; 34} // end anonymous namespace 35 36void ento::RegisterObjCAtSyncChecker(ExprEngine &Eng) { 37 // @synchronized is an Objective-C 2 feature. 38 if (Eng.getContext().getLangOptions().ObjC2) 39 Eng.registerCheck(new ObjCAtSyncChecker()); 40} 41 42void ObjCAtSyncChecker::PreVisitObjCAtSynchronizedStmt(CheckerContext &C, 43 const ObjCAtSynchronizedStmt *S) { 44 45 const Expr *Ex = S->getSynchExpr(); 46 const GRState *state = C.getState(); 47 SVal V = state->getSVal(Ex); 48 49 // Uninitialized value used for the mutex? 50 if (isa<UndefinedVal>(V)) { 51 if (ExplodedNode *N = C.generateSink()) { 52 if (!BT_undef) 53 BT_undef = new BuiltinBug("Uninitialized value used as mutex " 54 "for @synchronized"); 55 EnhancedBugReport *report = 56 new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N); 57 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex); 58 C.EmitReport(report); 59 } 60 return; 61 } 62 63 if (V.isUnknown()) 64 return; 65 66 // Check for null mutexes. 67 const GRState *notNullState, *nullState; 68 llvm::tie(notNullState, nullState) = state->assume(cast<DefinedSVal>(V)); 69 70 if (nullState) { 71 if (!notNullState) { 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)) { 75 if (!BT_null) 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, 81 Ex); 82 83 C.EmitReport(report); 84 return; 85 } 86 } 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 89 // afterwards. 90 } 91 92 if (notNullState) 93 C.addTransition(notNullState); 94} 95 96