Home | History | Annotate | Download | only in Checkers
      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 "ClangSACheckers.h"
     16 #include "clang/StaticAnalyzer/Core/Checker.h"
     17 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
     18 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
     19 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
     20 #include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h"
     21 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
     22 
     23 using namespace clang;
     24 using namespace ento;
     25 
     26 namespace {
     27 class ObjCAtSyncChecker
     28     : public Checker< check::PreStmt<ObjCAtSynchronizedStmt> > {
     29   mutable llvm::OwningPtr<BuiltinBug> BT_null;
     30   mutable llvm::OwningPtr<BuiltinBug> BT_undef;
     31 
     32 public:
     33   void checkPreStmt(const ObjCAtSynchronizedStmt *S, CheckerContext &C) const;
     34 };
     35 } // end anonymous namespace
     36 
     37 void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
     38                                      CheckerContext &C) const {
     39 
     40   const Expr *Ex = S->getSynchExpr();
     41   const ProgramState *state = C.getState();
     42   SVal V = state->getSVal(Ex);
     43 
     44   // Uninitialized value used for the mutex?
     45   if (isa<UndefinedVal>(V)) {
     46     if (ExplodedNode *N = C.generateSink()) {
     47       if (!BT_undef)
     48         BT_undef.reset(new BuiltinBug("Uninitialized value used as mutex "
     49                                   "for @synchronized"));
     50       BugReport *report =
     51         new BugReport(*BT_undef, BT_undef->getDescription(), N);
     52       report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex));
     53       C.EmitReport(report);
     54     }
     55     return;
     56   }
     57 
     58   if (V.isUnknown())
     59     return;
     60 
     61   // Check for null mutexes.
     62   const ProgramState *notNullState, *nullState;
     63   llvm::tie(notNullState, nullState) = state->assume(cast<DefinedSVal>(V));
     64 
     65   if (nullState) {
     66     if (!notNullState) {
     67       // Generate an error node.  This isn't a sink since
     68       // a null mutex just means no synchronization occurs.
     69       if (ExplodedNode *N = C.generateNode(nullState)) {
     70         if (!BT_null)
     71           BT_null.reset(new BuiltinBug("Nil value used as mutex for @synchronized() "
     72                                    "(no synchronization will occur)"));
     73         BugReport *report =
     74           new BugReport(*BT_null, BT_null->getDescription(), N);
     75         report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex));
     76 
     77         C.EmitReport(report);
     78         return;
     79       }
     80     }
     81     // Don't add a transition for 'nullState'.  If the value is
     82     // under-constrained to be null or non-null, assume it is non-null
     83     // afterwards.
     84   }
     85 
     86   if (notNullState)
     87     C.addTransition(notNullState);
     88 }
     89 
     90 void ento::registerObjCAtSyncChecker(CheckerManager &mgr) {
     91   if (mgr.getLangOptions().ObjC2)
     92     mgr.registerChecker<ObjCAtSyncChecker>();
     93 }
     94