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/BugReporter/BugType.h" 00018 #include "clang/StaticAnalyzer/Core/Checker.h" 00019 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00020 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 00021 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 00022 00023 using namespace clang; 00024 using namespace ento; 00025 00026 namespace { 00027 class ObjCAtSyncChecker 00028 : public Checker< check::PreStmt<ObjCAtSynchronizedStmt> > { 00029 mutable std::unique_ptr<BuiltinBug> BT_null; 00030 mutable std::unique_ptr<BuiltinBug> BT_undef; 00031 00032 public: 00033 void checkPreStmt(const ObjCAtSynchronizedStmt *S, CheckerContext &C) const; 00034 }; 00035 } // end anonymous namespace 00036 00037 void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, 00038 CheckerContext &C) const { 00039 00040 const Expr *Ex = S->getSynchExpr(); 00041 ProgramStateRef state = C.getState(); 00042 SVal V = state->getSVal(Ex, C.getLocationContext()); 00043 00044 // Uninitialized value used for the mutex? 00045 if (V.getAs<UndefinedVal>()) { 00046 if (ExplodedNode *N = C.generateSink()) { 00047 if (!BT_undef) 00048 BT_undef.reset(new BuiltinBug(this, "Uninitialized value used as mutex " 00049 "for @synchronized")); 00050 BugReport *report = 00051 new BugReport(*BT_undef, BT_undef->getDescription(), N); 00052 bugreporter::trackNullOrUndefValue(N, Ex, *report); 00053 C.emitReport(report); 00054 } 00055 return; 00056 } 00057 00058 if (V.isUnknown()) 00059 return; 00060 00061 // Check for null mutexes. 00062 ProgramStateRef notNullState, nullState; 00063 std::tie(notNullState, nullState) = state->assume(V.castAs<DefinedSVal>()); 00064 00065 if (nullState) { 00066 if (!notNullState) { 00067 // Generate an error node. This isn't a sink since 00068 // a null mutex just means no synchronization occurs. 00069 if (ExplodedNode *N = C.addTransition(nullState)) { 00070 if (!BT_null) 00071 BT_null.reset(new BuiltinBug( 00072 this, "Nil value used as mutex for @synchronized() " 00073 "(no synchronization will occur)")); 00074 BugReport *report = 00075 new BugReport(*BT_null, BT_null->getDescription(), N); 00076 bugreporter::trackNullOrUndefValue(N, Ex, *report); 00077 00078 C.emitReport(report); 00079 return; 00080 } 00081 } 00082 // Don't add a transition for 'nullState'. If the value is 00083 // under-constrained to be null or non-null, assume it is non-null 00084 // afterwards. 00085 } 00086 00087 if (notNullState) 00088 C.addTransition(notNullState); 00089 } 00090 00091 void ento::registerObjCAtSyncChecker(CheckerManager &mgr) { 00092 if (mgr.getLangOpts().ObjC2) 00093 mgr.registerChecker<ObjCAtSyncChecker>(); 00094 }