33#include "llvm/Support/FormatVariadic.h"
45class UnconditionalVAArgChecker
46 :
public Checker<check::BeginFunction, check::EndFunction,
47 check::BranchCondition, check::PreStmt<VAArgExpr>> {
48 const BugType BT{
this,
"Unconditional use of va_arg()",
51 static const FunctionDecl *getCurrentFunction(CheckerContext &
C);
54 void checkBeginFunction(CheckerContext &
C)
const;
55 void checkEndFunction(
const ReturnStmt *, CheckerContext &
C)
const;
56 void checkBranchCondition(
const Stmt *
Condition, CheckerContext &
C)
const;
57 void checkPreStmt(
const VAArgExpr *VAA, CheckerContext &
C)
const;
63 const Decl *FD =
C.getLocationContext()->getDecl();
64 return dyn_cast_if_present<FunctionDecl>(FD);
67void UnconditionalVAArgChecker::checkBeginFunction(CheckerContext &
C)
const {
71 const FunctionDecl *FD = getCurrentFunction(
C);
81 C.addTransition(
C.getState()->set<HasUnconditionalPath>(FD));
85void UnconditionalVAArgChecker::checkEndFunction(
const ReturnStmt *,
86 CheckerContext &
C)
const {
93 const FunctionDecl *FD = getCurrentFunction(
C);
94 if (FD && FD == State->get<HasUnconditionalPath>()) {
95 State = State->set<HasUnconditionalPath>(
nullptr);
96 C.addTransition(State);
100void UnconditionalVAArgChecker::checkBranchCondition(
const Stmt *
Condition,
101 CheckerContext &
C)
const {
121 C.addTransition(
C.getState()->set<HasUnconditionalPath>(
nullptr));
124void UnconditionalVAArgChecker::checkPreStmt(
const VAArgExpr *VAA,
125 CheckerContext &
C)
const {
127 const FunctionDecl *PathFrom = State->get<HasUnconditionalPath>();
133 C.addTransition(State->set<HasUnconditionalPath>(
nullptr));
140 std::string FullMsg = formatv(
141 "Calls to '{0}' always reach this va_arg() expression, so calling "
142 "'{0}' with no variadic arguments would be undefined behavior",
145 PathDiagnosticLocation PDL(SR.
getBegin(),
146 C.getASTContext().getSourceManager());
152 std::make_unique<BasicBugReport>(BT, BT.
getDescription(), FullMsg, PDL);
154 if (getCurrentFunction(
C) != PathFrom) {
158 PathDiagnosticLocation DefPDL(DefSR.
getBegin(),
159 C.getASTContext().getSourceManager());
160 std::string NoteMsg =
161 formatv(
"Variadic function '{0}' is defined here", FN);
162 R->addNote(NoteMsg, DefPDL, DefSR);
165 R->setDeclWithIssue(PathFrom);
166 C.emitReport(std::move(R));
169void ento::registerUnconditionalVAArgChecker(CheckerManager &Mgr) {
173bool ento::shouldRegisterUnconditionalVAArgChecker(
const CheckerManager &) {
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy.
Represents a function declaration or definition.
bool isVariadic() const
Whether this function is variadic.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
StringRef getName() const
Return the actual identifier string.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
SourceLocation getBegin() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
StringRef getDescription() const
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.
const char *const MemoryError
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.