xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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*bdd1243dSDimitry Andric #include <optional>
3281ad6265SDimitry Andric 
3381ad6265SDimitry Andric using namespace clang;
3481ad6265SDimitry Andric using namespace ento;
3581ad6265SDimitry Andric 
3681ad6265SDimitry Andric namespace {
3781ad6265SDimitry Andric 
3881ad6265SDimitry Andric // Name of the "errno" variable.
3981ad6265SDimitry Andric // FIXME: Is there a system where it is not called "errno" but is a variable?
4081ad6265SDimitry Andric const char *ErrnoVarName = "errno";
4181ad6265SDimitry Andric // Names of functions that return a location of the "errno" value.
4281ad6265SDimitry Andric // FIXME: Are there other similar function names?
4381ad6265SDimitry Andric const char *ErrnoLocationFuncNames[] = {"__errno_location", "___errno",
4481ad6265SDimitry Andric                                         "__errno", "_errno", "__error"};
4581ad6265SDimitry Andric 
4681ad6265SDimitry Andric class ErrnoModeling
4781ad6265SDimitry Andric     : public Checker<check::ASTDecl<TranslationUnitDecl>, check::BeginFunction,
4881ad6265SDimitry Andric                      check::LiveSymbols, eval::Call> {
4981ad6265SDimitry Andric public:
5081ad6265SDimitry Andric   void checkASTDecl(const TranslationUnitDecl *D, AnalysisManager &Mgr,
5181ad6265SDimitry Andric                     BugReporter &BR) const;
5281ad6265SDimitry Andric   void checkBeginFunction(CheckerContext &C) const;
5381ad6265SDimitry Andric   void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
5481ad6265SDimitry Andric   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
5581ad6265SDimitry Andric 
5681ad6265SDimitry Andric   // The declaration of an "errno" variable or "errno location" function.
5781ad6265SDimitry Andric   mutable const Decl *ErrnoDecl = nullptr;
5881ad6265SDimitry Andric 
5981ad6265SDimitry Andric private:
6081ad6265SDimitry Andric   // FIXME: Names from `ErrnoLocationFuncNames` are used to build this set.
61*bdd1243dSDimitry Andric   CallDescriptionSet ErrnoLocationCalls{{{"__errno_location"}, 0, 0},
62*bdd1243dSDimitry Andric                                         {{"___errno"}, 0, 0},
63*bdd1243dSDimitry Andric                                         {{"__errno"}, 0, 0},
64*bdd1243dSDimitry Andric                                         {{"_errno"}, 0, 0},
65*bdd1243dSDimitry Andric                                         {{"__error"}, 0, 0}};
6681ad6265SDimitry Andric };
6781ad6265SDimitry Andric 
6881ad6265SDimitry Andric } // namespace
6981ad6265SDimitry Andric 
7081ad6265SDimitry Andric /// Store a MemRegion that contains the 'errno' integer value.
7181ad6265SDimitry Andric /// The value is null if the 'errno' value was not recognized in the AST.
7281ad6265SDimitry Andric REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoRegion, const MemRegion *)
7381ad6265SDimitry Andric 
7481ad6265SDimitry Andric REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoState, errno_modeling::ErrnoCheckState)
7581ad6265SDimitry Andric 
7681ad6265SDimitry Andric /// Search for a variable called "errno" in the AST.
7781ad6265SDimitry Andric /// Return nullptr if not found.
7881ad6265SDimitry Andric static const VarDecl *getErrnoVar(ASTContext &ACtx) {
7981ad6265SDimitry Andric   IdentifierInfo &II = ACtx.Idents.get(ErrnoVarName);
8081ad6265SDimitry Andric   auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
8181ad6265SDimitry Andric   auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) {
8281ad6265SDimitry Andric     if (auto *VD = dyn_cast<VarDecl>(D))
8381ad6265SDimitry Andric       return ACtx.getSourceManager().isInSystemHeader(VD->getLocation()) &&
8481ad6265SDimitry Andric              VD->hasExternalStorage() &&
8581ad6265SDimitry Andric              VD->getType().getCanonicalType() == ACtx.IntTy;
8681ad6265SDimitry Andric     return false;
8781ad6265SDimitry Andric   });
8881ad6265SDimitry Andric   if (Found == LookupRes.end())
8981ad6265SDimitry Andric     return nullptr;
9081ad6265SDimitry Andric 
9181ad6265SDimitry Andric   return cast<VarDecl>(*Found);
9281ad6265SDimitry Andric }
9381ad6265SDimitry Andric 
9481ad6265SDimitry Andric /// Search for a function with a specific name that is used to return a pointer
9581ad6265SDimitry Andric /// to "errno".
9681ad6265SDimitry Andric /// Return nullptr if no such function was found.
9781ad6265SDimitry Andric static const FunctionDecl *getErrnoFunc(ASTContext &ACtx) {
9881ad6265SDimitry Andric   SmallVector<const Decl *> LookupRes;
9981ad6265SDimitry Andric   for (StringRef ErrnoName : ErrnoLocationFuncNames) {
10081ad6265SDimitry Andric     IdentifierInfo &II = ACtx.Idents.get(ErrnoName);
10181ad6265SDimitry Andric     llvm::append_range(LookupRes, ACtx.getTranslationUnitDecl()->lookup(&II));
10281ad6265SDimitry Andric   }
10381ad6265SDimitry Andric 
10481ad6265SDimitry Andric   auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) {
10581ad6265SDimitry Andric     if (auto *FD = dyn_cast<FunctionDecl>(D))
10681ad6265SDimitry Andric       return ACtx.getSourceManager().isInSystemHeader(FD->getLocation()) &&
10781ad6265SDimitry Andric              FD->isExternC() && FD->getNumParams() == 0 &&
10881ad6265SDimitry Andric              FD->getReturnType().getCanonicalType() ==
10981ad6265SDimitry Andric                  ACtx.getPointerType(ACtx.IntTy);
11081ad6265SDimitry Andric     return false;
11181ad6265SDimitry Andric   });
11281ad6265SDimitry Andric   if (Found == LookupRes.end())
11381ad6265SDimitry Andric     return nullptr;
11481ad6265SDimitry Andric 
11581ad6265SDimitry Andric   return cast<FunctionDecl>(*Found);
11681ad6265SDimitry Andric }
11781ad6265SDimitry Andric 
11881ad6265SDimitry Andric void ErrnoModeling::checkASTDecl(const TranslationUnitDecl *D,
11981ad6265SDimitry Andric                                  AnalysisManager &Mgr, BugReporter &BR) const {
12081ad6265SDimitry Andric   // Try to find an usable `errno` value.
12181ad6265SDimitry Andric   // It can be an external variable called "errno" or a function that returns a
12281ad6265SDimitry Andric   // pointer to the "errno" value. This function can have different names.
12381ad6265SDimitry Andric   // The actual case is dependent on the C library implementation, we
12481ad6265SDimitry Andric   // can only search for a match in one of these variations.
12581ad6265SDimitry Andric   // We assume that exactly one of these cases might be true.
12681ad6265SDimitry Andric   ErrnoDecl = getErrnoVar(Mgr.getASTContext());
12781ad6265SDimitry Andric   if (!ErrnoDecl)
12881ad6265SDimitry Andric     ErrnoDecl = getErrnoFunc(Mgr.getASTContext());
12981ad6265SDimitry Andric }
13081ad6265SDimitry Andric 
13181ad6265SDimitry Andric void ErrnoModeling::checkBeginFunction(CheckerContext &C) const {
13281ad6265SDimitry Andric   if (!C.inTopFrame())
13381ad6265SDimitry Andric     return;
13481ad6265SDimitry Andric 
13581ad6265SDimitry Andric   ASTContext &ACtx = C.getASTContext();
13681ad6265SDimitry Andric   ProgramStateRef State = C.getState();
13781ad6265SDimitry Andric 
13881ad6265SDimitry Andric   if (const auto *ErrnoVar = dyn_cast_or_null<VarDecl>(ErrnoDecl)) {
13981ad6265SDimitry Andric     // There is an external 'errno' variable.
14081ad6265SDimitry Andric     // Use its memory region.
14181ad6265SDimitry Andric     // The memory region for an 'errno'-like variable is allocated in system
14281ad6265SDimitry Andric     // space by MemRegionManager.
14381ad6265SDimitry Andric     const MemRegion *ErrnoR =
14481ad6265SDimitry Andric         State->getRegion(ErrnoVar, C.getLocationContext());
14581ad6265SDimitry Andric     assert(ErrnoR && "Memory region should exist for the 'errno' variable.");
14681ad6265SDimitry Andric     State = State->set<ErrnoRegion>(ErrnoR);
14781ad6265SDimitry Andric     State =
14881ad6265SDimitry Andric         errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant);
14981ad6265SDimitry Andric     C.addTransition(State);
15081ad6265SDimitry Andric   } else if (ErrnoDecl) {
15181ad6265SDimitry Andric     assert(isa<FunctionDecl>(ErrnoDecl) && "Invalid errno location function.");
15281ad6265SDimitry Andric     // There is a function that returns the location of 'errno'.
15381ad6265SDimitry Andric     // We must create a memory region for it in system space.
15481ad6265SDimitry Andric     // Currently a symbolic region is used with an artifical symbol.
15581ad6265SDimitry Andric     // FIXME: It is better to have a custom (new) kind of MemRegion for such
15681ad6265SDimitry Andric     // cases.
15781ad6265SDimitry Andric     SValBuilder &SVB = C.getSValBuilder();
15881ad6265SDimitry Andric     MemRegionManager &RMgr = C.getStateManager().getRegionManager();
15981ad6265SDimitry Andric 
16081ad6265SDimitry Andric     const MemSpaceRegion *GlobalSystemSpace =
16181ad6265SDimitry Andric         RMgr.getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind);
16281ad6265SDimitry Andric 
16381ad6265SDimitry Andric     // Create an artifical symbol for the region.
16481ad6265SDimitry Andric     // It is not possible to associate a statement or expression in this case.
16581ad6265SDimitry Andric     const SymbolConjured *Sym = SVB.conjureSymbol(
16681ad6265SDimitry Andric         nullptr, C.getLocationContext(),
16781ad6265SDimitry Andric         ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl);
16881ad6265SDimitry Andric 
16981ad6265SDimitry Andric     // The symbolic region is untyped, create a typed sub-region in it.
17081ad6265SDimitry Andric     // The ElementRegion is used to make the errno region a typed region.
17181ad6265SDimitry Andric     const MemRegion *ErrnoR = RMgr.getElementRegion(
17281ad6265SDimitry Andric         ACtx.IntTy, SVB.makeZeroArrayIndex(),
17381ad6265SDimitry Andric         RMgr.getSymbolicRegion(Sym, GlobalSystemSpace), C.getASTContext());
17481ad6265SDimitry Andric     State = State->set<ErrnoRegion>(ErrnoR);
17581ad6265SDimitry Andric     State =
17681ad6265SDimitry Andric         errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant);
17781ad6265SDimitry Andric     C.addTransition(State);
17881ad6265SDimitry Andric   }
17981ad6265SDimitry Andric }
18081ad6265SDimitry Andric 
18181ad6265SDimitry Andric bool ErrnoModeling::evalCall(const CallEvent &Call, CheckerContext &C) const {
18281ad6265SDimitry Andric   // Return location of "errno" at a call to an "errno address returning"
18381ad6265SDimitry Andric   // function.
18481ad6265SDimitry Andric   if (ErrnoLocationCalls.contains(Call)) {
18581ad6265SDimitry Andric     ProgramStateRef State = C.getState();
18681ad6265SDimitry Andric 
18781ad6265SDimitry Andric     const MemRegion *ErrnoR = State->get<ErrnoRegion>();
18881ad6265SDimitry Andric     if (!ErrnoR)
18981ad6265SDimitry Andric       return false;
19081ad6265SDimitry Andric 
19181ad6265SDimitry Andric     State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
19281ad6265SDimitry Andric                             loc::MemRegionVal{ErrnoR});
19381ad6265SDimitry Andric     C.addTransition(State);
19481ad6265SDimitry Andric     return true;
19581ad6265SDimitry Andric   }
19681ad6265SDimitry Andric 
19781ad6265SDimitry Andric   return false;
19881ad6265SDimitry Andric }
19981ad6265SDimitry Andric 
20081ad6265SDimitry Andric void ErrnoModeling::checkLiveSymbols(ProgramStateRef State,
20181ad6265SDimitry Andric                                      SymbolReaper &SR) const {
20281ad6265SDimitry Andric   // The special errno region should never garbage collected.
20381ad6265SDimitry Andric   if (const auto *ErrnoR = State->get<ErrnoRegion>())
20481ad6265SDimitry Andric     SR.markLive(ErrnoR);
20581ad6265SDimitry Andric }
20681ad6265SDimitry Andric 
20781ad6265SDimitry Andric namespace clang {
20881ad6265SDimitry Andric namespace ento {
20981ad6265SDimitry Andric namespace errno_modeling {
21081ad6265SDimitry Andric 
211*bdd1243dSDimitry Andric std::optional<SVal> getErrnoValue(ProgramStateRef State) {
21281ad6265SDimitry Andric   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
21381ad6265SDimitry Andric   if (!ErrnoR)
21481ad6265SDimitry Andric     return {};
21581ad6265SDimitry Andric   QualType IntTy = State->getAnalysisManager().getASTContext().IntTy;
21681ad6265SDimitry Andric   return State->getSVal(ErrnoR, IntTy);
21781ad6265SDimitry Andric }
21881ad6265SDimitry Andric 
21981ad6265SDimitry Andric ProgramStateRef setErrnoValue(ProgramStateRef State,
22081ad6265SDimitry Andric                               const LocationContext *LCtx, SVal Value,
22181ad6265SDimitry Andric                               ErrnoCheckState EState) {
22281ad6265SDimitry Andric   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
22381ad6265SDimitry Andric   if (!ErrnoR)
22481ad6265SDimitry Andric     return State;
22581ad6265SDimitry Andric   // First set the errno value, the old state is still available at 'checkBind'
22681ad6265SDimitry Andric   // or 'checkLocation' for errno value.
22781ad6265SDimitry Andric   State = State->bindLoc(loc::MemRegionVal{ErrnoR}, Value, LCtx);
22881ad6265SDimitry Andric   return State->set<ErrnoState>(EState);
22981ad6265SDimitry Andric }
23081ad6265SDimitry Andric 
23181ad6265SDimitry Andric ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C,
23281ad6265SDimitry Andric                               uint64_t Value, ErrnoCheckState EState) {
23381ad6265SDimitry Andric   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
23481ad6265SDimitry Andric   if (!ErrnoR)
23581ad6265SDimitry Andric     return State;
23681ad6265SDimitry Andric   State = State->bindLoc(
23781ad6265SDimitry Andric       loc::MemRegionVal{ErrnoR},
23881ad6265SDimitry Andric       C.getSValBuilder().makeIntVal(Value, C.getASTContext().IntTy),
23981ad6265SDimitry Andric       C.getLocationContext());
24081ad6265SDimitry Andric   return State->set<ErrnoState>(EState);
24181ad6265SDimitry Andric }
24281ad6265SDimitry Andric 
243*bdd1243dSDimitry Andric std::optional<Loc> getErrnoLoc(ProgramStateRef State) {
24481ad6265SDimitry Andric   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
24581ad6265SDimitry Andric   if (!ErrnoR)
24681ad6265SDimitry Andric     return {};
24781ad6265SDimitry Andric   return loc::MemRegionVal{ErrnoR};
24881ad6265SDimitry Andric }
24981ad6265SDimitry Andric 
250*bdd1243dSDimitry Andric ErrnoCheckState getErrnoState(ProgramStateRef State) {
251*bdd1243dSDimitry Andric   return State->get<ErrnoState>();
252*bdd1243dSDimitry Andric }
253*bdd1243dSDimitry Andric 
25481ad6265SDimitry Andric ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState) {
25581ad6265SDimitry Andric   return State->set<ErrnoState>(EState);
25681ad6265SDimitry Andric }
25781ad6265SDimitry Andric 
258*bdd1243dSDimitry Andric ProgramStateRef clearErrnoState(ProgramStateRef State) {
259*bdd1243dSDimitry Andric   return setErrnoState(State, Irrelevant);
26081ad6265SDimitry Andric }
26181ad6265SDimitry Andric 
26281ad6265SDimitry Andric bool isErrno(const Decl *D) {
26381ad6265SDimitry Andric   if (const auto *VD = dyn_cast_or_null<VarDecl>(D))
26481ad6265SDimitry Andric     if (const IdentifierInfo *II = VD->getIdentifier())
26581ad6265SDimitry Andric       return II->getName() == ErrnoVarName;
26681ad6265SDimitry Andric   if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D))
26781ad6265SDimitry Andric     if (const IdentifierInfo *II = FD->getIdentifier())
26881ad6265SDimitry Andric       return llvm::is_contained(ErrnoLocationFuncNames, II->getName());
26981ad6265SDimitry Andric   return false;
27081ad6265SDimitry Andric }
27181ad6265SDimitry Andric 
272*bdd1243dSDimitry Andric const char *describeErrnoCheckState(ErrnoCheckState CS) {
273*bdd1243dSDimitry Andric   assert(CS == errno_modeling::MustNotBeChecked &&
274*bdd1243dSDimitry Andric          "Errno description not applicable.");
275*bdd1243dSDimitry Andric   return "may be undefined after the call and should not be used";
276*bdd1243dSDimitry Andric }
277*bdd1243dSDimitry Andric 
27881ad6265SDimitry Andric const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message) {
27981ad6265SDimitry Andric   return C.getNoteTag([Message](PathSensitiveBugReport &BR) -> std::string {
28081ad6265SDimitry Andric     const MemRegion *ErrnoR = BR.getErrorNode()->getState()->get<ErrnoRegion>();
28181ad6265SDimitry Andric     if (ErrnoR && BR.isInteresting(ErrnoR)) {
28281ad6265SDimitry Andric       BR.markNotInteresting(ErrnoR);
28381ad6265SDimitry Andric       return Message;
28481ad6265SDimitry Andric     }
28581ad6265SDimitry Andric     return "";
28681ad6265SDimitry Andric   });
28781ad6265SDimitry Andric }
28881ad6265SDimitry Andric 
289*bdd1243dSDimitry Andric ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State,
290*bdd1243dSDimitry Andric                                       CheckerContext &C) {
291*bdd1243dSDimitry Andric   return setErrnoState(State, MustNotBeChecked);
292*bdd1243dSDimitry Andric }
293*bdd1243dSDimitry Andric 
294*bdd1243dSDimitry Andric ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C,
295*bdd1243dSDimitry Andric                                       NonLoc ErrnoSym) {
296*bdd1243dSDimitry Andric   SValBuilder &SVB = C.getSValBuilder();
297*bdd1243dSDimitry Andric   NonLoc ZeroVal = SVB.makeZeroVal(C.getASTContext().IntTy).castAs<NonLoc>();
298*bdd1243dSDimitry Andric   DefinedOrUnknownSVal Cond =
299*bdd1243dSDimitry Andric       SVB.evalBinOp(State, BO_NE, ErrnoSym, ZeroVal, SVB.getConditionType())
300*bdd1243dSDimitry Andric           .castAs<DefinedOrUnknownSVal>();
301*bdd1243dSDimitry Andric   State = State->assume(Cond, true);
302*bdd1243dSDimitry Andric   if (!State)
303*bdd1243dSDimitry Andric     return nullptr;
304*bdd1243dSDimitry Andric   return setErrnoValue(State, C.getLocationContext(), ErrnoSym, Irrelevant);
305*bdd1243dSDimitry Andric }
306*bdd1243dSDimitry Andric 
307*bdd1243dSDimitry Andric ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State,
308*bdd1243dSDimitry Andric                                          CheckerContext &C,
309*bdd1243dSDimitry Andric                                          const Expr *InvalE) {
310*bdd1243dSDimitry Andric   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
311*bdd1243dSDimitry Andric   if (!ErrnoR)
312*bdd1243dSDimitry Andric     return State;
313*bdd1243dSDimitry Andric   State = State->invalidateRegions(ErrnoR, InvalE, C.blockCount(),
314*bdd1243dSDimitry Andric                                    C.getLocationContext(), false);
315*bdd1243dSDimitry Andric   if (!State)
316*bdd1243dSDimitry Andric     return nullptr;
317*bdd1243dSDimitry Andric   return setErrnoState(State, MustBeChecked);
318*bdd1243dSDimitry Andric }
319*bdd1243dSDimitry Andric 
320*bdd1243dSDimitry Andric const NoteTag *getNoteTagForStdSuccess(CheckerContext &C, llvm::StringRef Fn) {
321*bdd1243dSDimitry Andric   return getErrnoNoteTag(
322*bdd1243dSDimitry Andric       C, (Twine("Assuming that function '") + Twine(Fn) +
323*bdd1243dSDimitry Andric           Twine("' is successful, in this case the value 'errno' ") +
324*bdd1243dSDimitry Andric           Twine(describeErrnoCheckState(MustNotBeChecked)))
325*bdd1243dSDimitry Andric              .str());
326*bdd1243dSDimitry Andric }
327*bdd1243dSDimitry Andric 
328*bdd1243dSDimitry Andric const NoteTag *getNoteTagForStdMustBeChecked(CheckerContext &C,
329*bdd1243dSDimitry Andric                                              llvm::StringRef Fn) {
330*bdd1243dSDimitry Andric   return getErrnoNoteTag(
331*bdd1243dSDimitry Andric       C, (Twine("Function '") + Twine(Fn) +
332*bdd1243dSDimitry Andric           Twine("' indicates failure only by setting of 'errno'"))
333*bdd1243dSDimitry Andric              .str());
334*bdd1243dSDimitry Andric }
335*bdd1243dSDimitry Andric 
33681ad6265SDimitry Andric } // namespace errno_modeling
33781ad6265SDimitry Andric } // namespace ento
33881ad6265SDimitry Andric } // namespace clang
33981ad6265SDimitry Andric 
34081ad6265SDimitry Andric void ento::registerErrnoModeling(CheckerManager &mgr) {
34181ad6265SDimitry Andric   mgr.registerChecker<ErrnoModeling>();
34281ad6265SDimitry Andric }
34381ad6265SDimitry Andric 
34481ad6265SDimitry Andric bool ento::shouldRegisterErrnoModeling(const CheckerManager &mgr) {
34581ad6265SDimitry Andric   return true;
34681ad6265SDimitry Andric }
347