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/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 }