clang 20.0.0 (based on r547379) from build 12806354. Bug: http://b/379133546 Test: N/A Change-Id: I2eb8938af55d809de674be63cb30cf27e801862b Upstream-Commit: ad834e67b1105d15ef907f6255d4c96e8e733f57
566 lines
18 KiB
C++
566 lines
18 KiB
C++
//== Checker.h - Registration mechanism for checkers -------------*- 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 file defines Checker, used to create and register checkers.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKER_H
|
|
#define LLVM_CLANG_STATICANALYZER_CORE_CHECKER_H
|
|
|
|
#include "clang/Analysis/ProgramPoint.h"
|
|
#include "clang/Basic/LangOptions.h"
|
|
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
|
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
namespace clang {
|
|
namespace ento {
|
|
class BugReporter;
|
|
|
|
namespace check {
|
|
|
|
template <typename DECL>
|
|
class ASTDecl {
|
|
template <typename CHECKER>
|
|
static void _checkDecl(void *checker, const Decl *D, AnalysisManager& mgr,
|
|
BugReporter &BR) {
|
|
((const CHECKER *)checker)->checkASTDecl(cast<DECL>(D), mgr, BR);
|
|
}
|
|
|
|
static bool _handlesDecl(const Decl *D) {
|
|
return isa<DECL>(D);
|
|
}
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForDecl(CheckerManager::CheckDeclFunc(checker,
|
|
_checkDecl<CHECKER>),
|
|
_handlesDecl);
|
|
}
|
|
};
|
|
|
|
class ASTCodeBody {
|
|
template <typename CHECKER>
|
|
static void _checkBody(void *checker, const Decl *D, AnalysisManager& mgr,
|
|
BugReporter &BR) {
|
|
((const CHECKER *)checker)->checkASTCodeBody(D, mgr, BR);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForBody(CheckerManager::CheckDeclFunc(checker,
|
|
_checkBody<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class EndOfTranslationUnit {
|
|
template <typename CHECKER>
|
|
static void _checkEndOfTranslationUnit(void *checker,
|
|
const TranslationUnitDecl *TU,
|
|
AnalysisManager& mgr,
|
|
BugReporter &BR) {
|
|
((const CHECKER *)checker)->checkEndOfTranslationUnit(TU, mgr, BR);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr){
|
|
mgr._registerForEndOfTranslationUnit(
|
|
CheckerManager::CheckEndOfTranslationUnit(checker,
|
|
_checkEndOfTranslationUnit<CHECKER>));
|
|
}
|
|
};
|
|
|
|
template <typename STMT>
|
|
class PreStmt {
|
|
template <typename CHECKER>
|
|
static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) {
|
|
((const CHECKER *)checker)->checkPreStmt(cast<STMT>(S), C);
|
|
}
|
|
|
|
static bool _handlesStmt(const Stmt *S) {
|
|
return isa<STMT>(S);
|
|
}
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForPreStmt(CheckerManager::CheckStmtFunc(checker,
|
|
_checkStmt<CHECKER>),
|
|
_handlesStmt);
|
|
}
|
|
};
|
|
|
|
template <typename STMT>
|
|
class PostStmt {
|
|
template <typename CHECKER>
|
|
static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) {
|
|
((const CHECKER *)checker)->checkPostStmt(cast<STMT>(S), C);
|
|
}
|
|
|
|
static bool _handlesStmt(const Stmt *S) {
|
|
return isa<STMT>(S);
|
|
}
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForPostStmt(CheckerManager::CheckStmtFunc(checker,
|
|
_checkStmt<CHECKER>),
|
|
_handlesStmt);
|
|
}
|
|
};
|
|
|
|
class PreObjCMessage {
|
|
template <typename CHECKER>
|
|
static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg,
|
|
CheckerContext &C) {
|
|
((const CHECKER *)checker)->checkPreObjCMessage(msg, C);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForPreObjCMessage(
|
|
CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class ObjCMessageNil {
|
|
template <typename CHECKER>
|
|
static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg,
|
|
CheckerContext &C) {
|
|
((const CHECKER *)checker)->checkObjCMessageNil(msg, C);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForObjCMessageNil(
|
|
CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class PostObjCMessage {
|
|
template <typename CHECKER>
|
|
static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg,
|
|
CheckerContext &C) {
|
|
((const CHECKER *)checker)->checkPostObjCMessage(msg, C);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForPostObjCMessage(
|
|
CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class PreCall {
|
|
template <typename CHECKER>
|
|
static void _checkCall(void *checker, const CallEvent &msg,
|
|
CheckerContext &C) {
|
|
((const CHECKER *)checker)->checkPreCall(msg, C);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForPreCall(
|
|
CheckerManager::CheckCallFunc(checker, _checkCall<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class PostCall {
|
|
template <typename CHECKER>
|
|
static void _checkCall(void *checker, const CallEvent &msg,
|
|
CheckerContext &C) {
|
|
((const CHECKER *)checker)->checkPostCall(msg, C);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForPostCall(
|
|
CheckerManager::CheckCallFunc(checker, _checkCall<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class Location {
|
|
template <typename CHECKER>
|
|
static void _checkLocation(void *checker, SVal location, bool isLoad,
|
|
const Stmt *S, CheckerContext &C) {
|
|
((const CHECKER *)checker)->checkLocation(location, isLoad, S, C);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForLocation(
|
|
CheckerManager::CheckLocationFunc(checker, _checkLocation<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class Bind {
|
|
template <typename CHECKER>
|
|
static void _checkBind(void *checker, SVal location, SVal val, const Stmt *S,
|
|
CheckerContext &C) {
|
|
((const CHECKER *)checker)->checkBind(location, val, S, C);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForBind(
|
|
CheckerManager::CheckBindFunc(checker, _checkBind<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class EndAnalysis {
|
|
template <typename CHECKER>
|
|
static void _checkEndAnalysis(void *checker, ExplodedGraph &G,
|
|
BugReporter &BR, ExprEngine &Eng) {
|
|
((const CHECKER *)checker)->checkEndAnalysis(G, BR, Eng);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForEndAnalysis(
|
|
CheckerManager::CheckEndAnalysisFunc(checker, _checkEndAnalysis<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class BeginFunction {
|
|
template <typename CHECKER>
|
|
static void _checkBeginFunction(void *checker, CheckerContext &C) {
|
|
((const CHECKER *)checker)->checkBeginFunction(C);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForBeginFunction(CheckerManager::CheckBeginFunctionFunc(
|
|
checker, _checkBeginFunction<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class EndFunction {
|
|
template <typename CHECKER>
|
|
static void _checkEndFunction(void *checker, const ReturnStmt *RS,
|
|
CheckerContext &C) {
|
|
((const CHECKER *)checker)->checkEndFunction(RS, C);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForEndFunction(
|
|
CheckerManager::CheckEndFunctionFunc(checker, _checkEndFunction<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class BranchCondition {
|
|
template <typename CHECKER>
|
|
static void _checkBranchCondition(void *checker, const Stmt *Condition,
|
|
CheckerContext & C) {
|
|
((const CHECKER *)checker)->checkBranchCondition(Condition, C);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForBranchCondition(
|
|
CheckerManager::CheckBranchConditionFunc(checker,
|
|
_checkBranchCondition<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class NewAllocator {
|
|
template <typename CHECKER>
|
|
static void _checkNewAllocator(void *checker, const CXXAllocatorCall &Call,
|
|
CheckerContext &C) {
|
|
((const CHECKER *)checker)->checkNewAllocator(Call, C);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForNewAllocator(
|
|
CheckerManager::CheckNewAllocatorFunc(checker,
|
|
_checkNewAllocator<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class LiveSymbols {
|
|
template <typename CHECKER>
|
|
static void _checkLiveSymbols(void *checker, ProgramStateRef state,
|
|
SymbolReaper &SR) {
|
|
((const CHECKER *)checker)->checkLiveSymbols(state, SR);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForLiveSymbols(
|
|
CheckerManager::CheckLiveSymbolsFunc(checker, _checkLiveSymbols<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class DeadSymbols {
|
|
template <typename CHECKER>
|
|
static void _checkDeadSymbols(void *checker,
|
|
SymbolReaper &SR, CheckerContext &C) {
|
|
((const CHECKER *)checker)->checkDeadSymbols(SR, C);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForDeadSymbols(
|
|
CheckerManager::CheckDeadSymbolsFunc(checker, _checkDeadSymbols<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class RegionChanges {
|
|
template <typename CHECKER>
|
|
static ProgramStateRef
|
|
_checkRegionChanges(void *checker,
|
|
ProgramStateRef state,
|
|
const InvalidatedSymbols *invalidated,
|
|
ArrayRef<const MemRegion *> Explicits,
|
|
ArrayRef<const MemRegion *> Regions,
|
|
const LocationContext *LCtx,
|
|
const CallEvent *Call) {
|
|
return ((const CHECKER *) checker)->checkRegionChanges(state, invalidated,
|
|
Explicits, Regions,
|
|
LCtx, Call);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForRegionChanges(
|
|
CheckerManager::CheckRegionChangesFunc(checker,
|
|
_checkRegionChanges<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class PointerEscape {
|
|
template <typename CHECKER>
|
|
static ProgramStateRef
|
|
_checkPointerEscape(void *Checker,
|
|
ProgramStateRef State,
|
|
const InvalidatedSymbols &Escaped,
|
|
const CallEvent *Call,
|
|
PointerEscapeKind Kind,
|
|
RegionAndSymbolInvalidationTraits *ETraits) {
|
|
|
|
if (!ETraits)
|
|
return ((const CHECKER *)Checker)->checkPointerEscape(State,
|
|
Escaped,
|
|
Call,
|
|
Kind);
|
|
|
|
InvalidatedSymbols RegularEscape;
|
|
for (SymbolRef Sym : Escaped)
|
|
if (!ETraits->hasTrait(
|
|
Sym, RegionAndSymbolInvalidationTraits::TK_PreserveContents) &&
|
|
!ETraits->hasTrait(
|
|
Sym, RegionAndSymbolInvalidationTraits::TK_SuppressEscape))
|
|
RegularEscape.insert(Sym);
|
|
|
|
if (RegularEscape.empty())
|
|
return State;
|
|
|
|
return ((const CHECKER *)Checker)->checkPointerEscape(State,
|
|
RegularEscape,
|
|
Call,
|
|
Kind);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForPointerEscape(
|
|
CheckerManager::CheckPointerEscapeFunc(checker,
|
|
_checkPointerEscape<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class ConstPointerEscape {
|
|
template <typename CHECKER>
|
|
static ProgramStateRef
|
|
_checkConstPointerEscape(void *Checker,
|
|
ProgramStateRef State,
|
|
const InvalidatedSymbols &Escaped,
|
|
const CallEvent *Call,
|
|
PointerEscapeKind Kind,
|
|
RegionAndSymbolInvalidationTraits *ETraits) {
|
|
|
|
if (!ETraits)
|
|
return State;
|
|
|
|
InvalidatedSymbols ConstEscape;
|
|
for (SymbolRef Sym : Escaped) {
|
|
if (ETraits->hasTrait(
|
|
Sym, RegionAndSymbolInvalidationTraits::TK_PreserveContents) &&
|
|
!ETraits->hasTrait(
|
|
Sym, RegionAndSymbolInvalidationTraits::TK_SuppressEscape))
|
|
ConstEscape.insert(Sym);
|
|
}
|
|
|
|
if (ConstEscape.empty())
|
|
return State;
|
|
|
|
return ((const CHECKER *)Checker)->checkConstPointerEscape(State,
|
|
ConstEscape,
|
|
Call,
|
|
Kind);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForPointerEscape(
|
|
CheckerManager::CheckPointerEscapeFunc(checker,
|
|
_checkConstPointerEscape<CHECKER>));
|
|
}
|
|
};
|
|
|
|
|
|
template <typename EVENT>
|
|
class Event {
|
|
template <typename CHECKER>
|
|
static void _checkEvent(void *checker, const void *event) {
|
|
((const CHECKER *)checker)->checkEvent(*(const EVENT *)event);
|
|
}
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerListenerForEvent<EVENT>(
|
|
CheckerManager::CheckEventFunc(checker, _checkEvent<CHECKER>));
|
|
}
|
|
};
|
|
|
|
} // end check namespace
|
|
|
|
namespace eval {
|
|
|
|
class Assume {
|
|
template <typename CHECKER>
|
|
static ProgramStateRef _evalAssume(void *checker, ProgramStateRef state,
|
|
SVal cond, bool assumption) {
|
|
return ((const CHECKER *)checker)->evalAssume(state, cond, assumption);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForEvalAssume(
|
|
CheckerManager::EvalAssumeFunc(checker, _evalAssume<CHECKER>));
|
|
}
|
|
};
|
|
|
|
class Call {
|
|
template <typename CHECKER>
|
|
static bool _evalCall(void *checker, const CallEvent &Call,
|
|
CheckerContext &C) {
|
|
return ((const CHECKER *)checker)->evalCall(Call, C);
|
|
}
|
|
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerForEvalCall(
|
|
CheckerManager::EvalCallFunc(checker, _evalCall<CHECKER>));
|
|
}
|
|
};
|
|
|
|
} // end eval namespace
|
|
|
|
class CheckerBase : public ProgramPointTag {
|
|
CheckerNameRef Name;
|
|
friend class ::clang::ento::CheckerManager;
|
|
|
|
public:
|
|
StringRef getTagDescription() const override;
|
|
CheckerNameRef getCheckerName() const;
|
|
|
|
/// See CheckerManager::runCheckersForPrintState.
|
|
virtual void printState(raw_ostream &Out, ProgramStateRef State,
|
|
const char *NL, const char *Sep) const { }
|
|
};
|
|
|
|
/// Dump checker name to stream.
|
|
raw_ostream& operator<<(raw_ostream &Out, const CheckerBase &Checker);
|
|
|
|
/// Tag that can use a checker name as a message provider
|
|
/// (see SimpleProgramPointTag).
|
|
class CheckerProgramPointTag : public SimpleProgramPointTag {
|
|
public:
|
|
CheckerProgramPointTag(StringRef CheckerName, StringRef Msg);
|
|
CheckerProgramPointTag(const CheckerBase *Checker, StringRef Msg);
|
|
};
|
|
|
|
template <typename CHECK1, typename... CHECKs>
|
|
class Checker : public CHECK1, public CHECKs..., public CheckerBase {
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
CHECK1::_register(checker, mgr);
|
|
Checker<CHECKs...>::_register(checker, mgr);
|
|
}
|
|
};
|
|
|
|
template <typename CHECK1>
|
|
class Checker<CHECK1> : public CHECK1, public CheckerBase {
|
|
public:
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
CHECK1::_register(checker, mgr);
|
|
}
|
|
};
|
|
|
|
template <typename EVENT>
|
|
class EventDispatcher {
|
|
CheckerManager *Mgr = nullptr;
|
|
public:
|
|
EventDispatcher() = default;
|
|
|
|
template <typename CHECKER>
|
|
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
|
mgr._registerDispatcherForEvent<EVENT>();
|
|
static_cast<EventDispatcher<EVENT> *>(checker)->Mgr = &mgr;
|
|
}
|
|
|
|
void dispatchEvent(const EVENT &event) const {
|
|
Mgr->_dispatchEvent(event);
|
|
}
|
|
};
|
|
|
|
/// We dereferenced a location that may be null.
|
|
struct ImplicitNullDerefEvent {
|
|
SVal Location;
|
|
bool IsLoad;
|
|
ExplodedNode *SinkNode;
|
|
BugReporter *BR;
|
|
// When true, the dereference is in the source code directly. When false, the
|
|
// dereference might happen later (for example pointer passed to a parameter
|
|
// that is marked with nonnull attribute.)
|
|
bool IsDirectDereference;
|
|
|
|
static int Tag;
|
|
};
|
|
|
|
} // end ento namespace
|
|
|
|
} // end clang namespace
|
|
|
|
#endif
|