26#include "llvm/Support/FormatVariadic.h"
38class ConstraintBasedEQEvaluator {
39 const DefinedOrUnknownSVal CompareValue;
44 ConstraintBasedEQEvaluator(CheckerContext &
C,
45 const DefinedOrUnknownSVal CompareValue)
46 : CompareValue(CompareValue), PS(
C.getState()), SVB(
C.getSValBuilder()) {}
48 bool operator()(
const llvm::APSInt &EnumDeclInitValue) {
49 DefinedOrUnknownSVal EnumDeclValue = SVB.makeIntVal(EnumDeclInitValue);
50 DefinedOrUnknownSVal ElemEqualsValueToCast =
51 SVB.evalEQ(PS, EnumDeclValue, CompareValue);
53 return static_cast<bool>(PS->assume(ElemEqualsValueToCast,
true));
63class EnumCastOutOfRangeChecker :
public Checker<check::PreStmt<CastExpr>> {
64 const BugType EnumValueCastOutOfRange{
this,
"Enum cast out of range"};
65 void reportWarning(CheckerContext &
C,
const CastExpr *CE,
66 const EnumDecl *E)
const;
69 void checkPreStmt(
const CastExpr *CE, CheckerContext &
C)
const;
75EnumValueVector getDeclValuesForEnum(
const EnumDecl *ED) {
76 EnumValueVector DeclValues(
78 llvm::transform(ED->
enumerators(), DeclValues.begin(),
87 assert(E &&
"valid EnumDecl* is expected");
88 if (
const ExplodedNode *N =
C.generateNonFatalErrorNode()) {
89 std::string ValueStr =
"", NameStr =
"the enum";
92 const auto ConcreteValue =
93 C.getSVal(CE->
getSubExpr()).getAs<nonloc::ConcreteInt>();
95 ValueStr = formatv(
" '{0}'", ConcreteValue->getValue());
97 if (StringRef EnumName{E->
getName()}; !EnumName.empty()) {
98 NameStr = formatv(
"'{0}'", EnumName);
101 std::string Msg = formatv(
"The value{0} provided to the cast expression is "
102 "not in the valid range of values for {1}",
105 auto BR = std::make_unique<PathSensitiveBugReport>(EnumValueCastOutOfRange,
108 BR->addNote(
"enum declared here",
110 {E->getSourceRange()});
111 C.emitReport(std::move(BR));
115void EnumCastOutOfRangeChecker::checkPreStmt(
const CastExpr *CE,
116 CheckerContext &
C)
const {
125 case CK_IntegralCast:
134 const std::optional<DefinedOrUnknownSVal> ValueToCast =
135 C.getSVal(CE->
getSubExpr()).getAs<DefinedOrUnknownSVal>();
148 if (ED->hasAttr<FlagEnumAttr>())
151 EnumValueVector DeclValues = getDeclValuesForEnum(ED);
160 if (DeclValues.size() == 0)
164 bool PossibleValueMatch =
165 llvm::any_of(DeclValues, ConstraintBasedEQEvaluator(
C, *ValueToCast));
169 if (!PossibleValueMatch)
170 reportWarning(
C, CE, ED);
173void ento::registerEnumCastOutOfRangeChecker(CheckerManager &mgr) {
177bool ento::shouldRegisterEnumCastOutOfRangeChecker(
const CheckerManager &mgr) {
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
CastKind getCastKind() const
An instance of this object exists for each enum constant that is defined.
enumerator_range enumerators() const
enumerator_iterator enumerator_begin() const
enumerator_iterator enumerator_end() const
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
EnumDecl * getAsEnumDecl() const
Retrieves the EnumDecl this type refers to.
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
The JSON file list parser is used to communicate input to InstallAPI.