39 using namespace clang;
44 class VforkChecker :
public Checker<check::PreCall, check::PostCall,
45 check::Bind, check::PreStmt<ReturnStmt>> {
46 mutable std::unique_ptr<BuiltinBug> BT;
47 mutable llvm::SmallSet<const IdentifierInfo *, 10> VforkWhitelist;
52 bool isVforkCall(
const Decl *D, CheckerContext &C)
const;
53 bool isCallWhitelisted(
const IdentifierInfo *II, CheckerContext &C)
const;
55 void reportBug(
const char *What, CheckerContext &C,
56 const char *Details =
nullptr)
const;
59 VforkChecker() : II_vfork(nullptr) {}
61 void checkPreCall(
const CallEvent &Call, CheckerContext &C)
const;
62 void checkPostCall(
const CallEvent &Call, CheckerContext &C)
const;
63 void checkBind(SVal L, SVal
V,
const Stmt *S, CheckerContext &C)
const;
64 void checkPreStmt(
const ReturnStmt *RS, CheckerContext &C)
const;
75 #define VFORK_RESULT_INVALID 0 76 #define VFORK_RESULT_NONE ((void *)(uintptr_t)1) 82 bool VforkChecker::isVforkCall(
const Decl *D, CheckerContext &C)
const {
83 auto FD = dyn_cast_or_null<FunctionDecl>(D);
84 if (!FD || !C.isCLibraryFunction(FD))
92 return FD->getIdentifier() == II_vfork;
97 CheckerContext &C)
const {
98 if (VforkWhitelist.empty()) {
100 const char *ids[] = {
113 for (
const char **
id = ids; *
id; ++
id)
114 VforkWhitelist.insert(&AC.
Idents.
get(*
id));
117 return VforkWhitelist.count(II);
120 void VforkChecker::reportBug(
const char *What, CheckerContext &C,
121 const char *Details)
const {
122 if (ExplodedNode *N = C.generateErrorNode(C.getState())) {
124 BT.reset(
new BuiltinBug(
this,
125 "Dangerous construct in a vforked process"));
128 llvm::raw_svector_ostream os(buf);
130 os << What <<
" is prohibited after a successful vfork";
133 os <<
"; " << Details;
135 auto Report = llvm::make_unique<BugReport>(*BT, os.str(), N);
137 C.emitReport(std::move(Report));
142 void VforkChecker::checkPostCall(
const CallEvent &Call,
143 CheckerContext &C)
const {
147 if (isChildProcess(State))
150 if (!isVforkCall(Call.getDecl(), C))
154 SVal VforkRetVal = Call.getReturnValue();
156 VforkRetVal.getAs<DefinedOrUnknownSVal>();
161 const ParentMap &PM = C.getLocationContext()->getParentMap();
167 MemRegionManager &M = C.getStoreManager().getRegionManager();
168 const MemRegion *LhsDeclReg =
170 ? M.getVarRegion(LhsDecl, C.getLocationContext())
175 std::tie(ParentState, ChildState) = C.getState()->assume(*DVal);
176 C.addTransition(ParentState);
177 ChildState = ChildState->set<VforkResultRegion>(LhsDeclReg);
178 C.addTransition(ChildState);
182 void VforkChecker::checkPreCall(
const CallEvent &Call,
183 CheckerContext &C)
const {
185 if (isChildProcess(State)
186 && !isCallWhitelisted(Call.getCalleeIdentifier(), C))
187 reportBug(
"This function call", C);
191 void VforkChecker::checkBind(SVal L, SVal
V,
const Stmt *S,
192 CheckerContext &C)
const {
194 if (!isChildProcess(State))
197 const MemRegion *VforkLhs =
198 static_cast<const MemRegion *
>(State->get<VforkResultRegion>());
199 const MemRegion *MR = L.getAsRegion();
202 if (!MR || MR == VforkLhs)
205 reportBug(
"This assignment", C);
209 void VforkChecker::checkPreStmt(
const ReturnStmt *RS, CheckerContext &C)
const {
211 if (isChildProcess(State))
212 reportBug(
"Return", C,
"call _exit() instead");
215 void ento::registerVforkChecker(CheckerManager &mgr) {
216 mgr.registerChecker<VforkChecker>();
219 bool ento::shouldRegisterVforkChecker(
const LangOptions &LO) {
Stmt - This represents one statement.
Decl - This represents one declaration (or definition), e.g.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Represents a variable declaration or definition.
One of these records is kept for each identifier that is lexed.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
std::pair< const clang::VarDecl *, const clang::Expr * > parseAssignment(const Stmt *S)
internal::Matcher< T > id(StringRef ID, const internal::BindableMatcher< T > &InnerMatcher)
If the provided matcher matches a node, binds the node to ID.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
#define VFORK_RESULT_INVALID
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy...
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
#define VFORK_RESULT_NONE
Dataflow Directional Tag Classes.
Stmt * getParentIgnoreParenCasts(Stmt *) const