xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp (revision d56a1c68247751e94c4fc46dda282643d3739689)
1d8a2afb2SBalázs Kéri //=== ErrnoModeling.cpp -----------------------------------------*- C++ -*-===//
2d8a2afb2SBalázs Kéri //
3d8a2afb2SBalázs Kéri // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4d8a2afb2SBalázs Kéri // See https://llvm.org/LICENSE.txt for license information.
5d8a2afb2SBalázs Kéri // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d8a2afb2SBalázs Kéri //
7d8a2afb2SBalázs Kéri //===----------------------------------------------------------------------===//
8d8a2afb2SBalázs Kéri //
9d8a2afb2SBalázs Kéri // This defines a checker `ErrnoModeling`, which is used to make the system
10d8a2afb2SBalázs Kéri // value 'errno' available to other checkers.
11d8a2afb2SBalázs Kéri // The 'errno' value is stored at a special memory region that is accessible
12d8a2afb2SBalázs Kéri // through the `errno_modeling` namespace. The memory region is either the
13d8a2afb2SBalázs Kéri // region of `errno` itself if it is a variable, otherwise an artifically
14d8a2afb2SBalázs Kéri // created region (in the system memory space). If `errno` is defined by using
15d8a2afb2SBalázs Kéri // a function which returns the address of it (this is always the case if it is
16d8a2afb2SBalázs Kéri // not a variable) this function is recognized and evaluated. In this way
17d8a2afb2SBalázs Kéri // `errno` becomes visible to the analysis and checkers can change its value.
18d8a2afb2SBalázs Kéri //
19d8a2afb2SBalázs Kéri //===----------------------------------------------------------------------===//
20d8a2afb2SBalázs Kéri 
21d8a2afb2SBalázs Kéri #include "ErrnoModeling.h"
22d8a2afb2SBalázs Kéri #include "clang/AST/ParentMapContext.h"
23d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
24d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Core/Checker.h"
25d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Core/CheckerManager.h"
26d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
27d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
28d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
29d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
30d8a2afb2SBalázs Kéri #include "llvm/ADT/STLExtras.h"
31d8a2afb2SBalázs Kéri 
32d8a2afb2SBalázs Kéri using namespace clang;
33d8a2afb2SBalázs Kéri using namespace ento;
34d8a2afb2SBalázs Kéri 
35d8a2afb2SBalázs Kéri namespace {
36d8a2afb2SBalázs Kéri 
37d8a2afb2SBalázs Kéri // Name of the "errno" variable.
38d8a2afb2SBalázs Kéri // FIXME: Is there a system where it is not called "errno" but is a variable?
39d8a2afb2SBalázs Kéri const char *ErrnoVarName = "errno";
40d8a2afb2SBalázs Kéri // Names of functions that return a location of the "errno" value.
41d8a2afb2SBalázs Kéri // FIXME: Are there other similar function names?
42d8a2afb2SBalázs Kéri const char *ErrnoLocationFuncNames[] = {"__errno_location", "___errno",
43d8a2afb2SBalázs Kéri                                         "__errno", "_errno", "__error"};
44d8a2afb2SBalázs Kéri 
45d8a2afb2SBalázs Kéri class ErrnoModeling
46d8a2afb2SBalázs Kéri     : public Checker<check::ASTDecl<TranslationUnitDecl>, check::BeginFunction,
47d8a2afb2SBalázs Kéri                      check::LiveSymbols, eval::Call> {
48d8a2afb2SBalázs Kéri public:
49d8a2afb2SBalázs Kéri   void checkASTDecl(const TranslationUnitDecl *D, AnalysisManager &Mgr,
50d8a2afb2SBalázs Kéri                     BugReporter &BR) const;
51d8a2afb2SBalázs Kéri   void checkBeginFunction(CheckerContext &C) const;
52d8a2afb2SBalázs Kéri   void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
53d8a2afb2SBalázs Kéri   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
54d8a2afb2SBalázs Kéri 
55d8a2afb2SBalázs Kéri   // The declaration of an "errno" variable or "errno location" function.
56d8a2afb2SBalázs Kéri   mutable const Decl *ErrnoDecl = nullptr;
57d8a2afb2SBalázs Kéri 
58d8a2afb2SBalázs Kéri private:
59d8a2afb2SBalázs Kéri   // FIXME: Names from `ErrnoLocationFuncNames` are used to build this set.
60d8a2afb2SBalázs Kéri   CallDescriptionSet ErrnoLocationCalls{{"__errno_location", 0, 0},
61d8a2afb2SBalázs Kéri                                         {"___errno", 0, 0},
62d8a2afb2SBalázs Kéri                                         {"__errno", 0, 0},
63d8a2afb2SBalázs Kéri                                         {"_errno", 0, 0},
64d8a2afb2SBalázs Kéri                                         {"__error", 0, 0}};
65d8a2afb2SBalázs Kéri };
66d8a2afb2SBalázs Kéri 
67d8a2afb2SBalázs Kéri } // namespace
68d8a2afb2SBalázs Kéri 
69d8a2afb2SBalázs Kéri /// Store a MemRegion that contains the 'errno' integer value.
70d8a2afb2SBalázs Kéri /// The value is null if the 'errno' value was not recognized in the AST.
71cf1f1b72SBalazs Benics REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoRegion, const MemRegion *)
72d8a2afb2SBalázs Kéri 
7360f3b071SBalázs Kéri REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoState, errno_modeling::ErrnoCheckState)
7460f3b071SBalázs Kéri 
75d8a2afb2SBalázs Kéri /// Search for a variable called "errno" in the AST.
76d8a2afb2SBalázs Kéri /// Return nullptr if not found.
77d8a2afb2SBalázs Kéri static const VarDecl *getErrnoVar(ASTContext &ACtx) {
78d8a2afb2SBalázs Kéri   IdentifierInfo &II = ACtx.Idents.get(ErrnoVarName);
79d8a2afb2SBalázs Kéri   auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
80d8a2afb2SBalázs Kéri   auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) {
81d8a2afb2SBalázs Kéri     if (auto *VD = dyn_cast<VarDecl>(D))
82d8a2afb2SBalázs Kéri       return ACtx.getSourceManager().isInSystemHeader(VD->getLocation()) &&
83d8a2afb2SBalázs Kéri              VD->hasExternalStorage() &&
84d8a2afb2SBalázs Kéri              VD->getType().getCanonicalType() == ACtx.IntTy;
85d8a2afb2SBalázs Kéri     return false;
86d8a2afb2SBalázs Kéri   });
87d8a2afb2SBalázs Kéri   if (Found == LookupRes.end())
88d8a2afb2SBalázs Kéri     return nullptr;
89d8a2afb2SBalázs Kéri 
90d8a2afb2SBalázs Kéri   return cast<VarDecl>(*Found);
91d8a2afb2SBalázs Kéri }
92d8a2afb2SBalázs Kéri 
93d8a2afb2SBalázs Kéri /// Search for a function with a specific name that is used to return a pointer
94d8a2afb2SBalázs Kéri /// to "errno".
95d8a2afb2SBalázs Kéri /// Return nullptr if no such function was found.
96d8a2afb2SBalázs Kéri static const FunctionDecl *getErrnoFunc(ASTContext &ACtx) {
97d8a2afb2SBalázs Kéri   SmallVector<const Decl *> LookupRes;
98d8a2afb2SBalázs Kéri   for (StringRef ErrnoName : ErrnoLocationFuncNames) {
99d8a2afb2SBalázs Kéri     IdentifierInfo &II = ACtx.Idents.get(ErrnoName);
100d8a2afb2SBalázs Kéri     llvm::append_range(LookupRes, ACtx.getTranslationUnitDecl()->lookup(&II));
101d8a2afb2SBalázs Kéri   }
102d8a2afb2SBalázs Kéri 
103d8a2afb2SBalázs Kéri   auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) {
104d8a2afb2SBalázs Kéri     if (auto *FD = dyn_cast<FunctionDecl>(D))
105d8a2afb2SBalázs Kéri       return ACtx.getSourceManager().isInSystemHeader(FD->getLocation()) &&
106d8a2afb2SBalázs Kéri              FD->isExternC() && FD->getNumParams() == 0 &&
107d8a2afb2SBalázs Kéri              FD->getReturnType().getCanonicalType() ==
108d8a2afb2SBalázs Kéri                  ACtx.getPointerType(ACtx.IntTy);
109d8a2afb2SBalázs Kéri     return false;
110d8a2afb2SBalázs Kéri   });
111d8a2afb2SBalázs Kéri   if (Found == LookupRes.end())
112d8a2afb2SBalázs Kéri     return nullptr;
113d8a2afb2SBalázs Kéri 
114d8a2afb2SBalázs Kéri   return cast<FunctionDecl>(*Found);
115d8a2afb2SBalázs Kéri }
116d8a2afb2SBalázs Kéri 
117d8a2afb2SBalázs Kéri void ErrnoModeling::checkASTDecl(const TranslationUnitDecl *D,
118d8a2afb2SBalázs Kéri                                  AnalysisManager &Mgr, BugReporter &BR) const {
119d8a2afb2SBalázs Kéri   // Try to find an usable `errno` value.
120d8a2afb2SBalázs Kéri   // It can be an external variable called "errno" or a function that returns a
121d8a2afb2SBalázs Kéri   // pointer to the "errno" value. This function can have different names.
122d8a2afb2SBalázs Kéri   // The actual case is dependent on the C library implementation, we
123d8a2afb2SBalázs Kéri   // can only search for a match in one of these variations.
124d8a2afb2SBalázs Kéri   // We assume that exactly one of these cases might be true.
125d8a2afb2SBalázs Kéri   ErrnoDecl = getErrnoVar(Mgr.getASTContext());
126d8a2afb2SBalázs Kéri   if (!ErrnoDecl)
127d8a2afb2SBalázs Kéri     ErrnoDecl = getErrnoFunc(Mgr.getASTContext());
128d8a2afb2SBalázs Kéri }
129d8a2afb2SBalázs Kéri 
130d8a2afb2SBalázs Kéri void ErrnoModeling::checkBeginFunction(CheckerContext &C) const {
131d8a2afb2SBalázs Kéri   if (!C.inTopFrame())
132d8a2afb2SBalázs Kéri     return;
133d8a2afb2SBalázs Kéri 
134d8a2afb2SBalázs Kéri   ASTContext &ACtx = C.getASTContext();
135d8a2afb2SBalázs Kéri   ProgramStateRef State = C.getState();
136d8a2afb2SBalázs Kéri 
137d8a2afb2SBalázs Kéri   if (const auto *ErrnoVar = dyn_cast_or_null<VarDecl>(ErrnoDecl)) {
138d8a2afb2SBalázs Kéri     // There is an external 'errno' variable.
139d8a2afb2SBalázs Kéri     // Use its memory region.
140d8a2afb2SBalázs Kéri     // The memory region for an 'errno'-like variable is allocated in system
141d8a2afb2SBalázs Kéri     // space by MemRegionManager.
142d8a2afb2SBalázs Kéri     const MemRegion *ErrnoR =
143d8a2afb2SBalázs Kéri         State->getRegion(ErrnoVar, C.getLocationContext());
144d8a2afb2SBalázs Kéri     assert(ErrnoR && "Memory region should exist for the 'errno' variable.");
145d8a2afb2SBalázs Kéri     State = State->set<ErrnoRegion>(ErrnoR);
14660f3b071SBalázs Kéri     State =
14760f3b071SBalázs Kéri         errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant);
148d8a2afb2SBalázs Kéri     C.addTransition(State);
149d8a2afb2SBalázs Kéri   } else if (ErrnoDecl) {
150d8a2afb2SBalázs Kéri     assert(isa<FunctionDecl>(ErrnoDecl) && "Invalid errno location function.");
151d8a2afb2SBalázs Kéri     // There is a function that returns the location of 'errno'.
152d8a2afb2SBalázs Kéri     // We must create a memory region for it in system space.
153d8a2afb2SBalázs Kéri     // Currently a symbolic region is used with an artifical symbol.
154d8a2afb2SBalázs Kéri     // FIXME: It is better to have a custom (new) kind of MemRegion for such
155d8a2afb2SBalázs Kéri     // cases.
156d8a2afb2SBalázs Kéri     SValBuilder &SVB = C.getSValBuilder();
157d8a2afb2SBalázs Kéri     MemRegionManager &RMgr = C.getStateManager().getRegionManager();
158d8a2afb2SBalázs Kéri 
159d8a2afb2SBalázs Kéri     const MemSpaceRegion *GlobalSystemSpace =
160d8a2afb2SBalázs Kéri         RMgr.getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind);
161d8a2afb2SBalázs Kéri 
162d8a2afb2SBalázs Kéri     // Create an artifical symbol for the region.
163d8a2afb2SBalázs Kéri     // It is not possible to associate a statement or expression in this case.
164d8a2afb2SBalázs Kéri     const SymbolConjured *Sym = SVB.conjureSymbol(
165d8a2afb2SBalázs Kéri         nullptr, C.getLocationContext(),
166d8a2afb2SBalázs Kéri         ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl);
167d8a2afb2SBalázs Kéri 
168d8a2afb2SBalázs Kéri     // The symbolic region is untyped, create a typed sub-region in it.
169d8a2afb2SBalázs Kéri     // The ElementRegion is used to make the errno region a typed region.
170d8a2afb2SBalázs Kéri     const MemRegion *ErrnoR = RMgr.getElementRegion(
171d8a2afb2SBalázs Kéri         ACtx.IntTy, SVB.makeZeroArrayIndex(),
172d8a2afb2SBalázs Kéri         RMgr.getSymbolicRegion(Sym, GlobalSystemSpace), C.getASTContext());
173d8a2afb2SBalázs Kéri     State = State->set<ErrnoRegion>(ErrnoR);
17460f3b071SBalázs Kéri     State =
17560f3b071SBalázs Kéri         errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant);
176d8a2afb2SBalázs Kéri     C.addTransition(State);
177d8a2afb2SBalázs Kéri   }
178d8a2afb2SBalázs Kéri }
179d8a2afb2SBalázs Kéri 
180d8a2afb2SBalázs Kéri bool ErrnoModeling::evalCall(const CallEvent &Call, CheckerContext &C) const {
181d8a2afb2SBalázs Kéri   // Return location of "errno" at a call to an "errno address returning"
182d8a2afb2SBalázs Kéri   // function.
183d8a2afb2SBalázs Kéri   if (ErrnoLocationCalls.contains(Call)) {
184d8a2afb2SBalázs Kéri     ProgramStateRef State = C.getState();
185d8a2afb2SBalázs Kéri 
186cf1f1b72SBalazs Benics     const MemRegion *ErrnoR = State->get<ErrnoRegion>();
187d8a2afb2SBalázs Kéri     if (!ErrnoR)
188d8a2afb2SBalázs Kéri       return false;
189d8a2afb2SBalázs Kéri 
190d8a2afb2SBalázs Kéri     State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
191d8a2afb2SBalázs Kéri                             loc::MemRegionVal{ErrnoR});
192d8a2afb2SBalázs Kéri     C.addTransition(State);
193d8a2afb2SBalázs Kéri     return true;
194d8a2afb2SBalázs Kéri   }
195d8a2afb2SBalázs Kéri 
196d8a2afb2SBalázs Kéri   return false;
197d8a2afb2SBalázs Kéri }
198d8a2afb2SBalázs Kéri 
199d8a2afb2SBalázs Kéri void ErrnoModeling::checkLiveSymbols(ProgramStateRef State,
200d8a2afb2SBalázs Kéri                                      SymbolReaper &SR) const {
201d8a2afb2SBalázs Kéri   // The special errno region should never garbage collected.
20260f3b071SBalázs Kéri   if (const auto *ErrnoR = State->get<ErrnoRegion>())
203d8a2afb2SBalázs Kéri     SR.markLive(ErrnoR);
204d8a2afb2SBalázs Kéri }
205d8a2afb2SBalázs Kéri 
206d8a2afb2SBalázs Kéri namespace clang {
207d8a2afb2SBalázs Kéri namespace ento {
208d8a2afb2SBalázs Kéri namespace errno_modeling {
209d8a2afb2SBalázs Kéri 
210d8a2afb2SBalázs Kéri Optional<SVal> getErrnoValue(ProgramStateRef State) {
211cf1f1b72SBalazs Benics   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
212d8a2afb2SBalázs Kéri   if (!ErrnoR)
213d8a2afb2SBalázs Kéri     return {};
214d8a2afb2SBalázs Kéri   QualType IntTy = State->getAnalysisManager().getASTContext().IntTy;
215d8a2afb2SBalázs Kéri   return State->getSVal(ErrnoR, IntTy);
216d8a2afb2SBalázs Kéri }
217d8a2afb2SBalázs Kéri 
218d8a2afb2SBalázs Kéri ProgramStateRef setErrnoValue(ProgramStateRef State,
21960f3b071SBalázs Kéri                               const LocationContext *LCtx, SVal Value,
22060f3b071SBalázs Kéri                               ErrnoCheckState EState) {
221cf1f1b72SBalazs Benics   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
222d8a2afb2SBalázs Kéri   if (!ErrnoR)
223d8a2afb2SBalázs Kéri     return State;
22460f3b071SBalázs Kéri   // First set the errno value, the old state is still available at 'checkBind'
22560f3b071SBalázs Kéri   // or 'checkLocation' for errno value.
22660f3b071SBalázs Kéri   State = State->bindLoc(loc::MemRegionVal{ErrnoR}, Value, LCtx);
22760f3b071SBalázs Kéri   return State->set<ErrnoState>(EState);
228d8a2afb2SBalázs Kéri }
229d8a2afb2SBalázs Kéri 
230d8a2afb2SBalázs Kéri ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C,
23160f3b071SBalázs Kéri                               uint64_t Value, ErrnoCheckState EState) {
232cf1f1b72SBalazs Benics   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
233d8a2afb2SBalázs Kéri   if (!ErrnoR)
234d8a2afb2SBalázs Kéri     return State;
23560f3b071SBalázs Kéri   State = State->bindLoc(
236d8a2afb2SBalázs Kéri       loc::MemRegionVal{ErrnoR},
237d8a2afb2SBalázs Kéri       C.getSValBuilder().makeIntVal(Value, C.getASTContext().IntTy),
238d8a2afb2SBalázs Kéri       C.getLocationContext());
23960f3b071SBalázs Kéri   return State->set<ErrnoState>(EState);
24060f3b071SBalázs Kéri }
24160f3b071SBalázs Kéri 
24260f3b071SBalázs Kéri Optional<Loc> getErrnoLoc(ProgramStateRef State) {
24360f3b071SBalázs Kéri   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
24460f3b071SBalázs Kéri   if (!ErrnoR)
24560f3b071SBalázs Kéri     return {};
24660f3b071SBalázs Kéri   return loc::MemRegionVal{ErrnoR};
24760f3b071SBalázs Kéri }
24860f3b071SBalázs Kéri 
24960f3b071SBalázs Kéri ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState) {
25060f3b071SBalázs Kéri   return State->set<ErrnoState>(EState);
25160f3b071SBalázs Kéri }
25260f3b071SBalázs Kéri 
25360f3b071SBalázs Kéri ErrnoCheckState getErrnoState(ProgramStateRef State) {
25460f3b071SBalázs Kéri   return State->get<ErrnoState>();
25560f3b071SBalázs Kéri }
25660f3b071SBalázs Kéri 
25760f3b071SBalázs Kéri bool isErrno(const Decl *D) {
25860f3b071SBalázs Kéri   if (const auto *VD = dyn_cast_or_null<VarDecl>(D))
25960f3b071SBalázs Kéri     if (const IdentifierInfo *II = VD->getIdentifier())
26060f3b071SBalázs Kéri       return II->getName() == ErrnoVarName;
26160f3b071SBalázs Kéri   if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D))
26260f3b071SBalázs Kéri     if (const IdentifierInfo *II = FD->getIdentifier())
26360f3b071SBalázs Kéri       return llvm::is_contained(ErrnoLocationFuncNames, II->getName());
26460f3b071SBalázs Kéri   return false;
26560f3b071SBalázs Kéri }
26660f3b071SBalázs Kéri 
267*d56a1c68SBalázs Kéri const char *describeErrnoCheckState(ErrnoCheckState CS) {
268*d56a1c68SBalázs Kéri   assert(CS == errno_modeling::MustNotBeChecked &&
269*d56a1c68SBalázs Kéri          "Errno description not applicable.");
270*d56a1c68SBalázs Kéri   return "may be undefined after the call and should not be used";
271*d56a1c68SBalázs Kéri }
272*d56a1c68SBalázs Kéri 
27360f3b071SBalázs Kéri const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message) {
27460f3b071SBalázs Kéri   return C.getNoteTag([Message](PathSensitiveBugReport &BR) -> std::string {
27560f3b071SBalázs Kéri     const MemRegion *ErrnoR = BR.getErrorNode()->getState()->get<ErrnoRegion>();
27660f3b071SBalázs Kéri     if (ErrnoR && BR.isInteresting(ErrnoR)) {
27760f3b071SBalázs Kéri       BR.markNotInteresting(ErrnoR);
27860f3b071SBalázs Kéri       return Message;
27960f3b071SBalázs Kéri     }
28060f3b071SBalázs Kéri     return "";
28160f3b071SBalázs Kéri   });
282d8a2afb2SBalázs Kéri }
283d8a2afb2SBalázs Kéri 
284*d56a1c68SBalázs Kéri ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State,
285*d56a1c68SBalázs Kéri                                       CheckerContext &C) {
286*d56a1c68SBalázs Kéri   return setErrnoState(State, MustNotBeChecked);
287*d56a1c68SBalázs Kéri }
288*d56a1c68SBalázs Kéri 
289*d56a1c68SBalázs Kéri ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C,
290*d56a1c68SBalázs Kéri                                       NonLoc ErrnoSym) {
291*d56a1c68SBalázs Kéri   SValBuilder &SVB = C.getSValBuilder();
292*d56a1c68SBalázs Kéri   NonLoc ZeroVal = SVB.makeZeroVal(C.getASTContext().IntTy).castAs<NonLoc>();
293*d56a1c68SBalázs Kéri   DefinedOrUnknownSVal Cond =
294*d56a1c68SBalázs Kéri       SVB.evalBinOp(State, BO_NE, ErrnoSym, ZeroVal, SVB.getConditionType())
295*d56a1c68SBalázs Kéri           .castAs<DefinedOrUnknownSVal>();
296*d56a1c68SBalázs Kéri   State = State->assume(Cond, true);
297*d56a1c68SBalázs Kéri   if (!State)
298*d56a1c68SBalázs Kéri     return nullptr;
299*d56a1c68SBalázs Kéri   return setErrnoValue(State, C.getLocationContext(), ErrnoSym, Irrelevant);
300*d56a1c68SBalázs Kéri }
301*d56a1c68SBalázs Kéri 
302*d56a1c68SBalázs Kéri const NoteTag *getNoteTagForStdSuccess(CheckerContext &C, llvm::StringRef Fn) {
303*d56a1c68SBalázs Kéri   return getErrnoNoteTag(
304*d56a1c68SBalázs Kéri       C, (Twine("Assuming that function '") + Twine(Fn) +
305*d56a1c68SBalázs Kéri           Twine("' is successful, in this case the value 'errno' ") +
306*d56a1c68SBalázs Kéri           Twine(describeErrnoCheckState(MustNotBeChecked)))
307*d56a1c68SBalázs Kéri              .str());
308*d56a1c68SBalázs Kéri }
309*d56a1c68SBalázs Kéri 
310d8a2afb2SBalázs Kéri } // namespace errno_modeling
311d8a2afb2SBalázs Kéri } // namespace ento
312d8a2afb2SBalázs Kéri } // namespace clang
313d8a2afb2SBalázs Kéri 
314d8a2afb2SBalázs Kéri void ento::registerErrnoModeling(CheckerManager &mgr) {
315d8a2afb2SBalázs Kéri   mgr.registerChecker<ErrnoModeling>();
316d8a2afb2SBalázs Kéri }
317d8a2afb2SBalázs Kéri 
318d8a2afb2SBalázs Kéri bool ento::shouldRegisterErrnoModeling(const CheckerManager &mgr) {
319d8a2afb2SBalázs Kéri   return true;
320d8a2afb2SBalázs Kéri }
321