1942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek//== ObjCAtSyncChecker.cpp - nil mutex checker for @synchronized -*- C++ -*--=//
2942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek//
3942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek//                     The LLVM Compiler Infrastructure
4942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek//
5942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek// This file is distributed under the University of Illinois Open Source
6942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek// License. See LICENSE.TXT for details.
7942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek//
8942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek//===----------------------------------------------------------------------===//
9942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek//
10942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek// This defines ObjCAtSyncChecker, a builtin check that checks for null pointers
11942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek// used as mutexes for @synchronized.
12942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek//
13942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek//===----------------------------------------------------------------------===//
14942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek
15027a6abdd6cedc0b8203da72eed6d15c796dce9dArgyrios Kyrtzidis#include "ClangSACheckers.h"
16c35fb7d67d515659ad2325b4f6ec97c9fe64fb63Benjamin Kramer#include "clang/AST/StmtObjC.h"
17ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/Checker.h"
18695fb502825a53ccd178ec1c85c77929d88acb71Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/CheckerManager.h"
1945d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
209b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
219b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
22942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek
23942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenekusing namespace clang;
249ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento;
25942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek
26942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremeneknamespace {
2745d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidisclass ObjCAtSyncChecker
28ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis    : public Checker< check::PreStmt<ObjCAtSynchronizedStmt> > {
296f42b62b6194f53bcbc349f5d17388e1936535d7Dylan Noblesmith  mutable OwningPtr<BuiltinBug> BT_null;
306f42b62b6194f53bcbc349f5d17388e1936535d7Dylan Noblesmith  mutable OwningPtr<BuiltinBug> BT_undef;
3145d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis
32942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenekpublic:
3345d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis  void checkPreStmt(const ObjCAtSynchronizedStmt *S, CheckerContext &C) const;
34942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek};
35942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek} // end anonymous namespace
36942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek
3745d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidisvoid ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
3845d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis                                     CheckerContext &C) const {
39942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek
40942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek  const Expr *Ex = S->getSynchExpr();
418bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ProgramStateRef state = C.getState();
425eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek  SVal V = state->getSVal(Ex, C.getLocationContext());
43942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek
44942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek  // Uninitialized value used for the mutex?
45942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek  if (isa<UndefinedVal>(V)) {
46d048c6ef5b6cfaa0cecb8cc1d4bdace32ed21d07Ted Kremenek    if (ExplodedNode *N = C.generateSink()) {
47942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek      if (!BT_undef)
4845d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis        BT_undef.reset(new BuiltinBug("Uninitialized value used as mutex "
4945d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis                                  "for @synchronized"));
50e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks      BugReport *report =
51e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks        new BugReport(*BT_undef, BT_undef->getDescription(), N);
52a1f81bb0e55749a1414b1b5124bb83b9052ff2acJordan Rose      bugreporter::trackNullOrUndefValue(N, Ex, *report);
53942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek      C.EmitReport(report);
54942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek    }
55942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek    return;
56942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek  }
57942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek
580d4f7671882a4e902f12504b46eb486dfbf58515Ted Kremenek  if (V.isUnknown())
590d4f7671882a4e902f12504b46eb486dfbf58515Ted Kremenek    return;
600d4f7671882a4e902f12504b46eb486dfbf58515Ted Kremenek
61942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek  // Check for null mutexes.
628bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ProgramStateRef notNullState, nullState;
6328f47b92e760ccf641ac91cb0fe1c12d9ca89795Ted Kremenek  llvm::tie(notNullState, nullState) = state->assume(cast<DefinedSVal>(V));
64942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek
65942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek  if (nullState) {
66942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek    if (!notNullState) {
67942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek      // Generate an error node.  This isn't a sink since
68942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek      // a null mutex just means no synchronization occurs.
690bd6b110e908892d4b5c8671a9f435a1d72ad16aAnna Zaks      if (ExplodedNode *N = C.addTransition(nullState)) {
70942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek        if (!BT_null)
7145d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis          BT_null.reset(new BuiltinBug("Nil value used as mutex for @synchronized() "
7245d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis                                   "(no synchronization will occur)"));
73e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks        BugReport *report =
74e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks          new BugReport(*BT_null, BT_null->getDescription(), N);
75a1f81bb0e55749a1414b1b5124bb83b9052ff2acJordan Rose        bugreporter::trackNullOrUndefValue(N, Ex, *report);
76942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek
77942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek        C.EmitReport(report);
781adee4b62016e7db899019b1d5a63c30bd61af06Ted Kremenek        return;
79942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek      }
80942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek    }
811adee4b62016e7db899019b1d5a63c30bd61af06Ted Kremenek    // Don't add a transition for 'nullState'.  If the value is
821adee4b62016e7db899019b1d5a63c30bd61af06Ted Kremenek    // under-constrained to be null or non-null, assume it is non-null
831adee4b62016e7db899019b1d5a63c30bd61af06Ted Kremenek    // afterwards.
84942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek  }
85942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek
86942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek  if (notNullState)
870bd6b110e908892d4b5c8671a9f435a1d72ad16aAnna Zaks    C.addTransition(notNullState);
88942e24d0ca23ebd9a8d8a180d35dad237235b94aTed Kremenek}
891adee4b62016e7db899019b1d5a63c30bd61af06Ted Kremenek
9045d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidisvoid ento::registerObjCAtSyncChecker(CheckerManager &mgr) {
914e4d08403ca5cfd4d558fa2936215d3a4e5a528dDavid Blaikie  if (mgr.getLangOpts().ObjC2)
9245d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis    mgr.registerChecker<ObjCAtSyncChecker>();
9345d9b4e44154939b91d6b8f63e7756feaca547f2Argyrios Kyrtzidis}
94