xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
181ad6265SDimitry Andric //=== ErrnoModeling.cpp -----------------------------------------*- C++ -*-===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This defines a checker `ErrnoModeling`, which is used to make the system
1081ad6265SDimitry Andric // value 'errno' available to other checkers.
1181ad6265SDimitry Andric // The 'errno' value is stored at a special memory region that is accessible
1281ad6265SDimitry Andric // through the `errno_modeling` namespace. The memory region is either the
1381ad6265SDimitry Andric // region of `errno` itself if it is a variable, otherwise an artifically
1481ad6265SDimitry Andric // created region (in the system memory space). If `errno` is defined by using
1581ad6265SDimitry Andric // a function which returns the address of it (this is always the case if it is
1681ad6265SDimitry Andric // not a variable) this function is recognized and evaluated. In this way
1781ad6265SDimitry Andric // `errno` becomes visible to the analysis and checkers can change its value.
1881ad6265SDimitry Andric //
1981ad6265SDimitry Andric //===----------------------------------------------------------------------===//
2081ad6265SDimitry Andric 
2181ad6265SDimitry Andric #include "ErrnoModeling.h"
2281ad6265SDimitry Andric #include "clang/AST/ParentMapContext.h"
2381ad6265SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
2481ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
2581ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
2681ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
2781ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
2881ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
2981ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
3081ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h"
31*06c3fb27SDimitry Andric #include "llvm/Support/FormatVariadic.h"
32bdd1243dSDimitry Andric #include <optional>
3381ad6265SDimitry Andric 
3481ad6265SDimitry Andric using namespace clang;
3581ad6265SDimitry Andric using namespace ento;
3681ad6265SDimitry Andric 
3781ad6265SDimitry Andric namespace {
3881ad6265SDimitry Andric 
3981ad6265SDimitry Andric // Name of the "errno" variable.
4081ad6265SDimitry Andric // FIXME: Is there a system where it is not called "errno" but is a variable?
4181ad6265SDimitry Andric const char *ErrnoVarName = "errno";
4281ad6265SDimitry Andric // Names of functions that return a location of the "errno" value.
4381ad6265SDimitry Andric // FIXME: Are there other similar function names?
4481ad6265SDimitry Andric const char *ErrnoLocationFuncNames[] = {"__errno_location", "___errno",
4581ad6265SDimitry Andric                                         "__errno", "_errno", "__error"};
4681ad6265SDimitry Andric 
4781ad6265SDimitry Andric class ErrnoModeling
4881ad6265SDimitry Andric     : public Checker<check::ASTDecl<TranslationUnitDecl>, check::BeginFunction,
4981ad6265SDimitry Andric                      check::LiveSymbols, eval::Call> {
5081ad6265SDimitry Andric public:
5181ad6265SDimitry Andric   void checkASTDecl(const TranslationUnitDecl *D, AnalysisManager &Mgr,
5281ad6265SDimitry Andric                     BugReporter &BR) const;
5381ad6265SDimitry Andric   void checkBeginFunction(CheckerContext &C) const;
5481ad6265SDimitry Andric   void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
5581ad6265SDimitry Andric   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
5681ad6265SDimitry Andric 
5781ad6265SDimitry Andric   // The declaration of an "errno" variable or "errno location" function.
5881ad6265SDimitry Andric   mutable const Decl *ErrnoDecl = nullptr;
5981ad6265SDimitry Andric 
6081ad6265SDimitry Andric private:
6181ad6265SDimitry Andric   // FIXME: Names from `ErrnoLocationFuncNames` are used to build this set.
62bdd1243dSDimitry Andric   CallDescriptionSet ErrnoLocationCalls{{{"__errno_location"}, 0, 0},
63bdd1243dSDimitry Andric                                         {{"___errno"}, 0, 0},
64bdd1243dSDimitry Andric                                         {{"__errno"}, 0, 0},
65bdd1243dSDimitry Andric                                         {{"_errno"}, 0, 0},
66bdd1243dSDimitry Andric                                         {{"__error"}, 0, 0}};
6781ad6265SDimitry Andric };
6881ad6265SDimitry Andric 
6981ad6265SDimitry Andric } // namespace
7081ad6265SDimitry Andric 
7181ad6265SDimitry Andric /// Store a MemRegion that contains the 'errno' integer value.
7281ad6265SDimitry Andric /// The value is null if the 'errno' value was not recognized in the AST.
7381ad6265SDimitry Andric REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoRegion, const MemRegion *)
7481ad6265SDimitry Andric 
7581ad6265SDimitry Andric REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoState, errno_modeling::ErrnoCheckState)
7681ad6265SDimitry Andric 
7781ad6265SDimitry Andric /// Search for a variable called "errno" in the AST.
7881ad6265SDimitry Andric /// Return nullptr if not found.
7981ad6265SDimitry Andric static const VarDecl *getErrnoVar(ASTContext &ACtx) {
8081ad6265SDimitry Andric   IdentifierInfo &II = ACtx.Idents.get(ErrnoVarName);
8181ad6265SDimitry Andric   auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
8281ad6265SDimitry Andric   auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) {
8381ad6265SDimitry Andric     if (auto *VD = dyn_cast<VarDecl>(D))
8481ad6265SDimitry Andric       return ACtx.getSourceManager().isInSystemHeader(VD->getLocation()) &&
8581ad6265SDimitry Andric              VD->hasExternalStorage() &&
8681ad6265SDimitry Andric              VD->getType().getCanonicalType() == ACtx.IntTy;
8781ad6265SDimitry Andric     return false;
8881ad6265SDimitry Andric   });
8981ad6265SDimitry Andric   if (Found == LookupRes.end())
9081ad6265SDimitry Andric     return nullptr;
9181ad6265SDimitry Andric 
9281ad6265SDimitry Andric   return cast<VarDecl>(*Found);
9381ad6265SDimitry Andric }
9481ad6265SDimitry Andric 
9581ad6265SDimitry Andric /// Search for a function with a specific name that is used to return a pointer
9681ad6265SDimitry Andric /// to "errno".
9781ad6265SDimitry Andric /// Return nullptr if no such function was found.
9881ad6265SDimitry Andric static const FunctionDecl *getErrnoFunc(ASTContext &ACtx) {
9981ad6265SDimitry Andric   SmallVector<const Decl *> LookupRes;
10081ad6265SDimitry Andric   for (StringRef ErrnoName : ErrnoLocationFuncNames) {
10181ad6265SDimitry Andric     IdentifierInfo &II = ACtx.Idents.get(ErrnoName);
10281ad6265SDimitry Andric     llvm::append_range(LookupRes, ACtx.getTranslationUnitDecl()->lookup(&II));
10381ad6265SDimitry Andric   }
10481ad6265SDimitry Andric 
10581ad6265SDimitry Andric   auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) {
10681ad6265SDimitry Andric     if (auto *FD = dyn_cast<FunctionDecl>(D))
10781ad6265SDimitry Andric       return ACtx.getSourceManager().isInSystemHeader(FD->getLocation()) &&
10881ad6265SDimitry Andric              FD->isExternC() && FD->getNumParams() == 0 &&
10981ad6265SDimitry Andric              FD->getReturnType().getCanonicalType() ==
11081ad6265SDimitry Andric                  ACtx.getPointerType(ACtx.IntTy);
11181ad6265SDimitry Andric     return false;
11281ad6265SDimitry Andric   });
11381ad6265SDimitry Andric   if (Found == LookupRes.end())
11481ad6265SDimitry Andric     return nullptr;
11581ad6265SDimitry Andric 
11681ad6265SDimitry Andric   return cast<FunctionDecl>(*Found);
11781ad6265SDimitry Andric }
11881ad6265SDimitry Andric 
11981ad6265SDimitry Andric void ErrnoModeling::checkASTDecl(const TranslationUnitDecl *D,
12081ad6265SDimitry Andric                                  AnalysisManager &Mgr, BugReporter &BR) const {
12181ad6265SDimitry Andric   // Try to find an usable `errno` value.
12281ad6265SDimitry Andric   // It can be an external variable called "errno" or a function that returns a
12381ad6265SDimitry Andric   // pointer to the "errno" value. This function can have different names.
12481ad6265SDimitry Andric   // The actual case is dependent on the C library implementation, we
12581ad6265SDimitry Andric   // can only search for a match in one of these variations.
12681ad6265SDimitry Andric   // We assume that exactly one of these cases might be true.
12781ad6265SDimitry Andric   ErrnoDecl = getErrnoVar(Mgr.getASTContext());
12881ad6265SDimitry Andric   if (!ErrnoDecl)
12981ad6265SDimitry Andric     ErrnoDecl = getErrnoFunc(Mgr.getASTContext());
13081ad6265SDimitry Andric }
13181ad6265SDimitry Andric 
13281ad6265SDimitry Andric void ErrnoModeling::checkBeginFunction(CheckerContext &C) const {
13381ad6265SDimitry Andric   if (!C.inTopFrame())
13481ad6265SDimitry Andric     return;
13581ad6265SDimitry Andric 
13681ad6265SDimitry Andric   ASTContext &ACtx = C.getASTContext();
13781ad6265SDimitry Andric   ProgramStateRef State = C.getState();
13881ad6265SDimitry Andric 
13981ad6265SDimitry Andric   if (const auto *ErrnoVar = dyn_cast_or_null<VarDecl>(ErrnoDecl)) {
14081ad6265SDimitry Andric     // There is an external 'errno' variable.
14181ad6265SDimitry Andric     // Use its memory region.
14281ad6265SDimitry Andric     // The memory region for an 'errno'-like variable is allocated in system
14381ad6265SDimitry Andric     // space by MemRegionManager.
14481ad6265SDimitry Andric     const MemRegion *ErrnoR =
14581ad6265SDimitry Andric         State->getRegion(ErrnoVar, C.getLocationContext());
14681ad6265SDimitry Andric     assert(ErrnoR && "Memory region should exist for the 'errno' variable.");
14781ad6265SDimitry Andric     State = State->set<ErrnoRegion>(ErrnoR);
14881ad6265SDimitry Andric     State =
14981ad6265SDimitry Andric         errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant);
15081ad6265SDimitry Andric     C.addTransition(State);
15181ad6265SDimitry Andric   } else if (ErrnoDecl) {
15281ad6265SDimitry Andric     assert(isa<FunctionDecl>(ErrnoDecl) && "Invalid errno location function.");
15381ad6265SDimitry Andric     // There is a function that returns the location of 'errno'.
15481ad6265SDimitry Andric     // We must create a memory region for it in system space.
15581ad6265SDimitry Andric     // Currently a symbolic region is used with an artifical symbol.
15681ad6265SDimitry Andric     // FIXME: It is better to have a custom (new) kind of MemRegion for such
15781ad6265SDimitry Andric     // cases.
15881ad6265SDimitry Andric     SValBuilder &SVB = C.getSValBuilder();
15981ad6265SDimitry Andric     MemRegionManager &RMgr = C.getStateManager().getRegionManager();
16081ad6265SDimitry Andric 
16181ad6265SDimitry Andric     const MemSpaceRegion *GlobalSystemSpace =
16281ad6265SDimitry Andric         RMgr.getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind);
16381ad6265SDimitry Andric 
16481ad6265SDimitry Andric     // Create an artifical symbol for the region.
16581ad6265SDimitry Andric     // It is not possible to associate a statement or expression in this case.
16681ad6265SDimitry Andric     const SymbolConjured *Sym = SVB.conjureSymbol(
16781ad6265SDimitry Andric         nullptr, C.getLocationContext(),
16881ad6265SDimitry Andric         ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl);
16981ad6265SDimitry Andric 
17081ad6265SDimitry Andric     // The symbolic region is untyped, create a typed sub-region in it.
17181ad6265SDimitry Andric     // The ElementRegion is used to make the errno region a typed region.
17281ad6265SDimitry Andric     const MemRegion *ErrnoR = RMgr.getElementRegion(
17381ad6265SDimitry Andric         ACtx.IntTy, SVB.makeZeroArrayIndex(),
17481ad6265SDimitry Andric         RMgr.getSymbolicRegion(Sym, GlobalSystemSpace), C.getASTContext());
17581ad6265SDimitry Andric     State = State->set<ErrnoRegion>(ErrnoR);
17681ad6265SDimitry Andric     State =
17781ad6265SDimitry Andric         errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant);
17881ad6265SDimitry Andric     C.addTransition(State);
17981ad6265SDimitry Andric   }
18081ad6265SDimitry Andric }
18181ad6265SDimitry Andric 
18281ad6265SDimitry Andric bool ErrnoModeling::evalCall(const CallEvent &Call, CheckerContext &C) const {
18381ad6265SDimitry Andric   // Return location of "errno" at a call to an "errno address returning"
18481ad6265SDimitry Andric   // function.
18581ad6265SDimitry Andric   if (ErrnoLocationCalls.contains(Call)) {
18681ad6265SDimitry Andric     ProgramStateRef State = C.getState();
18781ad6265SDimitry Andric 
18881ad6265SDimitry Andric     const MemRegion *ErrnoR = State->get<ErrnoRegion>();
18981ad6265SDimitry Andric     if (!ErrnoR)
19081ad6265SDimitry Andric       return false;
19181ad6265SDimitry Andric 
19281ad6265SDimitry Andric     State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
19381ad6265SDimitry Andric                             loc::MemRegionVal{ErrnoR});
19481ad6265SDimitry Andric     C.addTransition(State);
19581ad6265SDimitry Andric     return true;
19681ad6265SDimitry Andric   }
19781ad6265SDimitry Andric 
19881ad6265SDimitry Andric   return false;
19981ad6265SDimitry Andric }
20081ad6265SDimitry Andric 
20181ad6265SDimitry Andric void ErrnoModeling::checkLiveSymbols(ProgramStateRef State,
20281ad6265SDimitry Andric                                      SymbolReaper &SR) const {
20381ad6265SDimitry Andric   // The special errno region should never garbage collected.
20481ad6265SDimitry Andric   if (const auto *ErrnoR = State->get<ErrnoRegion>())
20581ad6265SDimitry Andric     SR.markLive(ErrnoR);
20681ad6265SDimitry Andric }
20781ad6265SDimitry Andric 
20881ad6265SDimitry Andric namespace clang {
20981ad6265SDimitry Andric namespace ento {
21081ad6265SDimitry Andric namespace errno_modeling {
21181ad6265SDimitry Andric 
212bdd1243dSDimitry Andric std::optional<SVal> getErrnoValue(ProgramStateRef State) {
21381ad6265SDimitry Andric   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
21481ad6265SDimitry Andric   if (!ErrnoR)
21581ad6265SDimitry Andric     return {};
21681ad6265SDimitry Andric   QualType IntTy = State->getAnalysisManager().getASTContext().IntTy;
21781ad6265SDimitry Andric   return State->getSVal(ErrnoR, IntTy);
21881ad6265SDimitry Andric }
21981ad6265SDimitry Andric 
22081ad6265SDimitry Andric ProgramStateRef setErrnoValue(ProgramStateRef State,
22181ad6265SDimitry Andric                               const LocationContext *LCtx, SVal Value,
22281ad6265SDimitry Andric                               ErrnoCheckState EState) {
22381ad6265SDimitry Andric   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
22481ad6265SDimitry Andric   if (!ErrnoR)
22581ad6265SDimitry Andric     return State;
22681ad6265SDimitry Andric   // First set the errno value, the old state is still available at 'checkBind'
22781ad6265SDimitry Andric   // or 'checkLocation' for errno value.
22881ad6265SDimitry Andric   State = State->bindLoc(loc::MemRegionVal{ErrnoR}, Value, LCtx);
22981ad6265SDimitry Andric   return State->set<ErrnoState>(EState);
23081ad6265SDimitry Andric }
23181ad6265SDimitry Andric 
23281ad6265SDimitry Andric ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C,
23381ad6265SDimitry Andric                               uint64_t Value, ErrnoCheckState EState) {
23481ad6265SDimitry Andric   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
23581ad6265SDimitry Andric   if (!ErrnoR)
23681ad6265SDimitry Andric     return State;
23781ad6265SDimitry Andric   State = State->bindLoc(
23881ad6265SDimitry Andric       loc::MemRegionVal{ErrnoR},
23981ad6265SDimitry Andric       C.getSValBuilder().makeIntVal(Value, C.getASTContext().IntTy),
24081ad6265SDimitry Andric       C.getLocationContext());
24181ad6265SDimitry Andric   return State->set<ErrnoState>(EState);
24281ad6265SDimitry Andric }
24381ad6265SDimitry Andric 
244bdd1243dSDimitry Andric std::optional<Loc> getErrnoLoc(ProgramStateRef State) {
24581ad6265SDimitry Andric   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
24681ad6265SDimitry Andric   if (!ErrnoR)
24781ad6265SDimitry Andric     return {};
24881ad6265SDimitry Andric   return loc::MemRegionVal{ErrnoR};
24981ad6265SDimitry Andric }
25081ad6265SDimitry Andric 
251bdd1243dSDimitry Andric ErrnoCheckState getErrnoState(ProgramStateRef State) {
252bdd1243dSDimitry Andric   return State->get<ErrnoState>();
253bdd1243dSDimitry Andric }
254bdd1243dSDimitry Andric 
25581ad6265SDimitry Andric ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState) {
25681ad6265SDimitry Andric   return State->set<ErrnoState>(EState);
25781ad6265SDimitry Andric }
25881ad6265SDimitry Andric 
259bdd1243dSDimitry Andric ProgramStateRef clearErrnoState(ProgramStateRef State) {
260bdd1243dSDimitry Andric   return setErrnoState(State, Irrelevant);
26181ad6265SDimitry Andric }
26281ad6265SDimitry Andric 
26381ad6265SDimitry Andric bool isErrno(const Decl *D) {
26481ad6265SDimitry Andric   if (const auto *VD = dyn_cast_or_null<VarDecl>(D))
26581ad6265SDimitry Andric     if (const IdentifierInfo *II = VD->getIdentifier())
26681ad6265SDimitry Andric       return II->getName() == ErrnoVarName;
26781ad6265SDimitry Andric   if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D))
26881ad6265SDimitry Andric     if (const IdentifierInfo *II = FD->getIdentifier())
26981ad6265SDimitry Andric       return llvm::is_contained(ErrnoLocationFuncNames, II->getName());
27081ad6265SDimitry Andric   return false;
27181ad6265SDimitry Andric }
27281ad6265SDimitry Andric 
27381ad6265SDimitry Andric const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message) {
27481ad6265SDimitry Andric   return C.getNoteTag([Message](PathSensitiveBugReport &BR) -> std::string {
27581ad6265SDimitry Andric     const MemRegion *ErrnoR = BR.getErrorNode()->getState()->get<ErrnoRegion>();
27681ad6265SDimitry Andric     if (ErrnoR && BR.isInteresting(ErrnoR)) {
27781ad6265SDimitry Andric       BR.markNotInteresting(ErrnoR);
27881ad6265SDimitry Andric       return Message;
27981ad6265SDimitry Andric     }
28081ad6265SDimitry Andric     return "";
28181ad6265SDimitry Andric   });
28281ad6265SDimitry Andric }
28381ad6265SDimitry Andric 
284bdd1243dSDimitry Andric ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State,
285bdd1243dSDimitry Andric                                       CheckerContext &C) {
286bdd1243dSDimitry Andric   return setErrnoState(State, MustNotBeChecked);
287bdd1243dSDimitry Andric }
288bdd1243dSDimitry Andric 
289bdd1243dSDimitry Andric ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C,
290bdd1243dSDimitry Andric                                       NonLoc ErrnoSym) {
291bdd1243dSDimitry Andric   SValBuilder &SVB = C.getSValBuilder();
292bdd1243dSDimitry Andric   NonLoc ZeroVal = SVB.makeZeroVal(C.getASTContext().IntTy).castAs<NonLoc>();
293bdd1243dSDimitry Andric   DefinedOrUnknownSVal Cond =
294bdd1243dSDimitry Andric       SVB.evalBinOp(State, BO_NE, ErrnoSym, ZeroVal, SVB.getConditionType())
295bdd1243dSDimitry Andric           .castAs<DefinedOrUnknownSVal>();
296bdd1243dSDimitry Andric   State = State->assume(Cond, true);
297bdd1243dSDimitry Andric   if (!State)
298bdd1243dSDimitry Andric     return nullptr;
299bdd1243dSDimitry Andric   return setErrnoValue(State, C.getLocationContext(), ErrnoSym, Irrelevant);
300bdd1243dSDimitry Andric }
301bdd1243dSDimitry Andric 
302bdd1243dSDimitry Andric ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State,
303bdd1243dSDimitry Andric                                          CheckerContext &C,
304bdd1243dSDimitry Andric                                          const Expr *InvalE) {
305bdd1243dSDimitry Andric   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
306bdd1243dSDimitry Andric   if (!ErrnoR)
307bdd1243dSDimitry Andric     return State;
308bdd1243dSDimitry Andric   State = State->invalidateRegions(ErrnoR, InvalE, C.blockCount(),
309bdd1243dSDimitry Andric                                    C.getLocationContext(), false);
310bdd1243dSDimitry Andric   if (!State)
311bdd1243dSDimitry Andric     return nullptr;
312bdd1243dSDimitry Andric   return setErrnoState(State, MustBeChecked);
313bdd1243dSDimitry Andric }
314bdd1243dSDimitry Andric 
315bdd1243dSDimitry Andric const NoteTag *getNoteTagForStdSuccess(CheckerContext &C, llvm::StringRef Fn) {
316bdd1243dSDimitry Andric   return getErrnoNoteTag(
317*06c3fb27SDimitry Andric       C, llvm::formatv(
318*06c3fb27SDimitry Andric              "'errno' may be undefined after successful call to '{0}'", Fn));
319bdd1243dSDimitry Andric }
320bdd1243dSDimitry Andric 
321bdd1243dSDimitry Andric const NoteTag *getNoteTagForStdMustBeChecked(CheckerContext &C,
322bdd1243dSDimitry Andric                                              llvm::StringRef Fn) {
323bdd1243dSDimitry Andric   return getErrnoNoteTag(
324*06c3fb27SDimitry Andric       C, llvm::formatv("'{0}' indicates failure only by setting 'errno'", Fn));
325bdd1243dSDimitry Andric }
326bdd1243dSDimitry Andric 
32781ad6265SDimitry Andric } // namespace errno_modeling
32881ad6265SDimitry Andric } // namespace ento
32981ad6265SDimitry Andric } // namespace clang
33081ad6265SDimitry Andric 
33181ad6265SDimitry Andric void ento::registerErrnoModeling(CheckerManager &mgr) {
33281ad6265SDimitry Andric   mgr.registerChecker<ErrnoModeling>();
33381ad6265SDimitry Andric }
33481ad6265SDimitry Andric 
33581ad6265SDimitry Andric bool ento::shouldRegisterErrnoModeling(const CheckerManager &mgr) {
33681ad6265SDimitry Andric   return true;
33781ad6265SDimitry Andric }
338