Files
clang-p2996/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
Kristof Umann 058a7a450a [analyzer] Supply all checkers with a shouldRegister function
Introduce the boolean ento::shouldRegister##CHECKERNAME(const LangOptions &LO)
function very similarly to ento::register##CHECKERNAME. This will force every
checker to implement this function, but maybe it isn't that bad: I saw a lot of
ObjC or C++ specific checkers that should probably not register themselves based
on some LangOptions (mine too), but they do anyways.

A big benefit of this is that all registry functions now register their checker,
once it is called, registration is guaranteed.

This patch is a part of a greater effort to reinvent checker registration, more
info here: D54438#1315953

Differential Revision: https://reviews.llvm.org/D55424

llvm-svn: 352277
2019-01-26 14:23:08 +00:00

97 lines
3.3 KiB
C++

//== ObjCAtSyncChecker.cpp - nil mutex checker for @synchronized -*- C++ -*--=//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This defines ObjCAtSyncChecker, a builtin check that checks for null pointers
// used as mutexes for @synchronized.
//
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/AST/StmtObjC.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
using namespace ento;
namespace {
class ObjCAtSyncChecker
: public Checker< check::PreStmt<ObjCAtSynchronizedStmt> > {
mutable std::unique_ptr<BuiltinBug> BT_null;
mutable std::unique_ptr<BuiltinBug> BT_undef;
public:
void checkPreStmt(const ObjCAtSynchronizedStmt *S, CheckerContext &C) const;
};
} // end anonymous namespace
void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
CheckerContext &C) const {
const Expr *Ex = S->getSynchExpr();
ProgramStateRef state = C.getState();
SVal V = C.getSVal(Ex);
// Uninitialized value used for the mutex?
if (V.getAs<UndefinedVal>()) {
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_undef)
BT_undef.reset(new BuiltinBug(this, "Uninitialized value used as mutex "
"for @synchronized"));
auto report =
llvm::make_unique<BugReport>(*BT_undef, BT_undef->getDescription(), N);
bugreporter::trackExpressionValue(N, Ex, *report);
C.emitReport(std::move(report));
}
return;
}
if (V.isUnknown())
return;
// Check for null mutexes.
ProgramStateRef notNullState, nullState;
std::tie(notNullState, nullState) = state->assume(V.castAs<DefinedSVal>());
if (nullState) {
if (!notNullState) {
// Generate an error node. This isn't a sink since
// a null mutex just means no synchronization occurs.
if (ExplodedNode *N = C.generateNonFatalErrorNode(nullState)) {
if (!BT_null)
BT_null.reset(new BuiltinBug(
this, "Nil value used as mutex for @synchronized() "
"(no synchronization will occur)"));
auto report =
llvm::make_unique<BugReport>(*BT_null, BT_null->getDescription(), N);
bugreporter::trackExpressionValue(N, Ex, *report);
C.emitReport(std::move(report));
return;
}
}
// Don't add a transition for 'nullState'. If the value is
// under-constrained to be null or non-null, assume it is non-null
// afterwards.
}
if (notNullState)
C.addTransition(notNullState);
}
void ento::registerObjCAtSyncChecker(CheckerManager &mgr) {
mgr.registerChecker<ObjCAtSyncChecker>();
}
bool ento::shouldRegisterObjCAtSyncChecker(const LangOptions &LO) {
return LO.ObjC;
}