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