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/AST/StmtObjC.h"
     17 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
     18 #include "clang/StaticAnalyzer/Core/Checker.h"
     19 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
     20 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.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 std::unique_ptr<BuiltinBug> BT_null;
     30   mutable std::unique_ptr<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   ProgramStateRef state = C.getState();
     42   SVal V = state->getSVal(Ex, C.getLocationContext());
     43 
     44   // Uninitialized value used for the mutex?
     45   if (V.getAs<UndefinedVal>()) {
     46     if (ExplodedNode *N = C.generateErrorNode()) {
     47       if (!BT_undef)
     48         BT_undef.reset(new BuiltinBug(this, "Uninitialized value used as mutex "
     49                                             "for @synchronized"));
     50       auto report =
     51           llvm::make_unique<BugReport>(*BT_undef, BT_undef->getDescription(), N);
     52       bugreporter::trackNullOrUndefValue(N, Ex, *report);
     53       C.emitReport(std::move(report));
     54     }
     55     return;
     56   }
     57 
     58   if (V.isUnknown())
     59     return;
     60 
     61   // Check for null mutexes.
     62   ProgramStateRef notNullState, nullState;
     63   std::tie(notNullState, nullState) = state->assume(V.castAs<DefinedSVal>());
     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.generateNonFatalErrorNode(nullState)) {
     70         if (!BT_null)
     71           BT_null.reset(new BuiltinBug(
     72               this, "Nil value used as mutex for @synchronized() "
     73                     "(no synchronization will occur)"));
     74         auto report =
     75             llvm::make_unique<BugReport>(*BT_null, BT_null->getDescription(), N);
     76         bugreporter::trackNullOrUndefValue(N, Ex, *report);
     77 
     78         C.emitReport(std::move(report));
     79         return;
     80       }
     81     }
     82     // Don't add a transition for 'nullState'.  If the value is
     83     // under-constrained to be null or non-null, assume it is non-null
     84     // afterwards.
     85   }
     86 
     87   if (notNullState)
     88     C.addTransition(notNullState);
     89 }
     90 
     91 void ento::registerObjCAtSyncChecker(CheckerManager &mgr) {
     92   if (mgr.getLangOpts().ObjC2)
     93     mgr.registerChecker<ObjCAtSyncChecker>();
     94 }
     95