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