40 using namespace clang;
45 class VforkChecker :
public Checker<check::PreCall, check::PostCall,
46 check::Bind, check::PreStmt<ReturnStmt>> {
47 mutable std::unique_ptr<BuiltinBug> BT;
48 mutable llvm::SmallSet<const IdentifierInfo *, 10> VforkWhitelist;
53 bool isVforkCall(
const Decl *D, CheckerContext &C)
const;
54 bool isCallWhitelisted(
const IdentifierInfo *II, CheckerContext &C)
const;
56 void reportBug(
const char *What, CheckerContext &C,
57 const char *Details =
nullptr)
const;
60 VforkChecker() : II_vfork(nullptr) {}
62 void checkPreCall(
const CallEvent &Call, CheckerContext &C)
const;
63 void checkPostCall(
const CallEvent &Call, CheckerContext &C)
const;
64 void checkBind(SVal L, SVal V,
const Stmt *S, CheckerContext &C)
const;
65 void checkPreStmt(
const ReturnStmt *RS, CheckerContext &C)
const;
76 #define VFORK_RESULT_INVALID 0 77 #define VFORK_RESULT_NONE ((void *)(uintptr_t)1) 83 bool VforkChecker::isVforkCall(
const Decl *D, CheckerContext &C)
const {
84 auto FD = dyn_cast_or_null<FunctionDecl>(D);
85 if (!FD || !C.isCLibraryFunction(FD))
93 return FD->getIdentifier() == II_vfork;
98 CheckerContext &C)
const {
99 if (VforkWhitelist.empty()) {
101 const char *ids[] = {
114 for (
const char **
id = ids; *
id; ++
id)
115 VforkWhitelist.insert(&AC.
Idents.
get(*
id));
118 return VforkWhitelist.count(II);
121 void VforkChecker::reportBug(
const char *What, CheckerContext &C,
122 const char *Details)
const {
123 if (ExplodedNode *N = C.generateErrorNode(C.getState())) {
125 BT.reset(
new BuiltinBug(
this,
126 "Dangerous construct in a vforked process"));
129 llvm::raw_svector_ostream os(buf);
131 os << What <<
" is prohibited after a successful vfork";
134 os <<
"; " << Details;
136 auto Report = llvm::make_unique<BugReport>(*BT, os.str(), N);
138 C.emitReport(std::move(Report));
143 void VforkChecker::checkPostCall(
const CallEvent &Call,
144 CheckerContext &C)
const {
148 if (isChildProcess(State))
151 if (!isVforkCall(Call.getDecl(), C))
155 SVal VforkRetVal = Call.getReturnValue();
157 VforkRetVal.getAs<DefinedOrUnknownSVal>();
162 const ParentMap &PM = C.getLocationContext()->getParentMap();
168 MemRegionManager &M = C.getStoreManager().getRegionManager();
169 const MemRegion *LhsDeclReg =
171 ? M.getVarRegion(LhsDecl, C.getLocationContext())
176 std::tie(ParentState, ChildState) = C.getState()->assume(*DVal);
177 C.addTransition(ParentState);
178 ChildState = ChildState->set<VforkResultRegion>(LhsDeclReg);
179 C.addTransition(ChildState);
183 void VforkChecker::checkPreCall(
const CallEvent &Call,
184 CheckerContext &C)
const {
186 if (isChildProcess(State)
187 && !isCallWhitelisted(Call.getCalleeIdentifier(), C))
188 reportBug(
"This function call", C);
192 void VforkChecker::checkBind(SVal L, SVal V,
const Stmt *S,
193 CheckerContext &C)
const {
195 if (!isChildProcess(State))
198 const MemRegion *VforkLhs =
199 static_cast<const MemRegion *
>(State->get<VforkResultRegion>());
200 const MemRegion *MR = L.getAsRegion();
203 if (!MR || MR == VforkLhs)
206 reportBug(
"This assignment", C);
210 void VforkChecker::checkPreStmt(
const ReturnStmt *RS, CheckerContext &C)
const {
212 if (isChildProcess(State))
213 reportBug(
"Return", C,
"call _exit() instead");
216 void ento::registerVforkChecker(CheckerManager &mgr) {
217 mgr.registerChecker<VforkChecker>();
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 ...
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