clang API Documentation
00001 //== ObjCAtSyncChecker.cpp - nil mutex checker for @synchronized -*- C++ -*--=// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This defines ObjCAtSyncChecker, a builtin check that checks for null pointers 00011 // used as mutexes for @synchronized. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "ClangSACheckers.h" 00016 #include "clang/AST/StmtObjC.h" 00017 #include "clang/StaticAnalyzer/Core/Checker.h" 00018 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00019 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 00020 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 00021 #include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h" 00022 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 00023 00024 using namespace clang; 00025 using namespace ento; 00026 00027 namespace { 00028 class ObjCAtSyncChecker 00029 : public Checker< check::PreStmt<ObjCAtSynchronizedStmt> > { 00030 mutable OwningPtr<BuiltinBug> BT_null; 00031 mutable OwningPtr<BuiltinBug> BT_undef; 00032 00033 public: 00034 void checkPreStmt(const ObjCAtSynchronizedStmt *S, CheckerContext &C) const; 00035 }; 00036 } // end anonymous namespace 00037 00038 void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, 00039 CheckerContext &C) const { 00040 00041 const Expr *Ex = S->getSynchExpr(); 00042 ProgramStateRef state = C.getState(); 00043 SVal V = state->getSVal(Ex, C.getLocationContext()); 00044 00045 // Uninitialized value used for the mutex? 00046 if (isa<UndefinedVal>(V)) { 00047 if (ExplodedNode *N = C.generateSink()) { 00048 if (!BT_undef) 00049 BT_undef.reset(new BuiltinBug("Uninitialized value used as mutex " 00050 "for @synchronized")); 00051 BugReport *report = 00052 new BugReport(*BT_undef, BT_undef->getDescription(), N); 00053 report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex, 00054 report)); 00055 C.EmitReport(report); 00056 } 00057 return; 00058 } 00059 00060 if (V.isUnknown()) 00061 return; 00062 00063 // Check for null mutexes. 00064 ProgramStateRef notNullState, nullState; 00065 llvm::tie(notNullState, nullState) = state->assume(cast<DefinedSVal>(V)); 00066 00067 if (nullState) { 00068 if (!notNullState) { 00069 // Generate an error node. This isn't a sink since 00070 // a null mutex just means no synchronization occurs. 00071 if (ExplodedNode *N = C.addTransition(nullState)) { 00072 if (!BT_null) 00073 BT_null.reset(new BuiltinBug("Nil value used as mutex for @synchronized() " 00074 "(no synchronization will occur)")); 00075 BugReport *report = 00076 new BugReport(*BT_null, BT_null->getDescription(), N); 00077 report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex, 00078 report)); 00079 00080 C.EmitReport(report); 00081 return; 00082 } 00083 } 00084 // Don't add a transition for 'nullState'. If the value is 00085 // under-constrained to be null or non-null, assume it is non-null 00086 // afterwards. 00087 } 00088 00089 if (notNullState) 00090 C.addTransition(notNullState); 00091 } 00092 00093 void ento::registerObjCAtSyncChecker(CheckerManager &mgr) { 00094 if (mgr.getLangOpts().ObjC2) 00095 mgr.registerChecker<ObjCAtSyncChecker>(); 00096 }