clang API Documentation

ObjCAtSyncChecker.cpp
Go to the documentation of this file.
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 }