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