45class VforkChecker :
public Checker<check::PreCall, check::PostCall,
46 check::Bind, check::PreStmt<ReturnStmt>> {
47 mutable std::unique_ptr<BugType> BT;
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 BT.reset(
new BugType(
this,
"Dangerous construct in a vforked process"));
130 llvm::raw_svector_ostream os(buf);
132 os << What <<
" is prohibited after a successful vfork";
135 os <<
"; " << Details;
137 auto Report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
139 C.emitReport(std::move(Report));
149 if (isChildProcess(State))
152 if (!isVforkCall(
Call.getDecl(),
C))
156 SVal VforkRetVal =
Call.getReturnValue();
157 std::optional<DefinedOrUnknownSVal> DVal =
163 const ParentMap &PM =
C.getLocationContext()->getParentMap();
177 std::tie(ParentState, ChildState) =
C.getState()->assume(*DVal);
178 C.addTransition(ParentState);
179 ChildState = ChildState->set<VforkResultRegion>(LhsDeclReg);
180 C.addTransition(ChildState);
188 if (isChildProcess(State) &&
189 !isCallExplicitelyAllowed(
Call.getCalleeIdentifier(),
C))
190 reportBug(
"This function call",
C);
197 if (!isChildProcess(State))
201 static_cast<const MemRegion *
>(State->get<VforkResultRegion>());
205 if (!MR || MR == VforkLhs)
208 reportBug(
"This assignment",
C);
214 if (isChildProcess(State))
215 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)