45class VforkChecker :
public Checker<check::PreCall, check::PostCall,
46 check::Bind, check::PreStmt<ReturnStmt>> {
47 const BugType BT{
this,
"Dangerous construct in a vforked process"};
48 mutable llvm::SmallSet<const IdentifierInfo *, 10> VforkAllowlist;
58 const char *Details =
nullptr)
const;
61 VforkChecker() =
default;
77#define VFORK_RESULT_INVALID 0
78#define VFORK_RESULT_NONE ((void *)(uintptr_t)1)
85 auto FD = dyn_cast_or_null<FunctionDecl>(
D);
86 if (!FD || !
C.isCLibraryFunction(FD))
91 II_vfork = &AC.Idents.get(
"vfork");
94 return FD->getIdentifier() == II_vfork;
98bool VforkChecker::isCallExplicitelyAllowed(
const IdentifierInfo *II,
100 if (VforkAllowlist.empty()) {
102 const char *ids[] = {
116 for (
const char **
id = ids; *id; ++id)
117 VforkAllowlist.insert(&AC.Idents.get(*
id));
120 return VforkAllowlist.count(II);
124 const char *Details)
const {
127 llvm::raw_svector_ostream os(buf);
129 os << What <<
" is prohibited after a successful vfork";
132 os <<
"; " << Details;
134 auto Report = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);
136 C.emitReport(std::move(Report));
146 if (isChildProcess(State))
149 if (!isVforkCall(
Call.getDecl(),
C))
153 SVal VforkRetVal =
Call.getReturnValue();
154 std::optional<DefinedOrUnknownSVal> DVal =
160 const ParentMap &PM =
C.getLocationContext()->getParentMap();
174 std::tie(ParentState, ChildState) =
C.getState()->assume(*DVal);
175 C.addTransition(ParentState);
176 ChildState = ChildState->set<VforkResultRegion>(LhsDeclReg);
177 C.addTransition(ChildState);
185 if (isChildProcess(State) &&
186 !isCallExplicitelyAllowed(
Call.getCalleeIdentifier(),
C))
187 reportBug(
"This function call",
C);
194 if (!isChildProcess(State))
198 static_cast<const MemRegion *
>(State->get<VforkResultRegion>());
202 if (!MR || MR == VforkLhs)
205 reportBug(
"This assignment",
C);
211 if (isChildProcess(State))
212 reportBug(
"Return",
C,
"call _exit() instead");
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy.
#define VFORK_RESULT_INVALID
#define VFORK_RESULT_NONE
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Decl - This represents one declaration (or definition), e.g.
One of these records is kept for each identifier that is lexed.
Stmt * getParentIgnoreParenCasts(Stmt *) const
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Stmt - This represents one statement.
Represents a variable declaration or definition.
Represents an abstract call to a function or method along a particular path.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
const VarRegion * getVarRegion(const VarDecl *VD, const LocationContext *LC)
getVarRegion - Retrieve or create the memory region associated with a specified VarDecl and LocationC...
MemRegion - The root abstract class for all memory regions.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
const MemRegion * getAsRegion() const
std::pair< const clang::VarDecl *, const clang::Expr * > parseAssignment(const Stmt *S)
The JSON file list parser is used to communicate input to InstallAPI.