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" 3106c3fb27SDimitry 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"; 42*0fca6ea1SDimitry Andric 4381ad6265SDimitry Andric // Names of functions that return a location of the "errno" value. 4481ad6265SDimitry Andric // FIXME: Are there other similar function names? 45*0fca6ea1SDimitry Andric CallDescriptionSet ErrnoLocationCalls{ 46*0fca6ea1SDimitry Andric {CDM::CLibrary, {"__errno_location"}, 0, 0}, 47*0fca6ea1SDimitry Andric {CDM::CLibrary, {"___errno"}, 0, 0}, 48*0fca6ea1SDimitry Andric {CDM::CLibrary, {"__errno"}, 0, 0}, 49*0fca6ea1SDimitry Andric {CDM::CLibrary, {"_errno"}, 0, 0}, 50*0fca6ea1SDimitry Andric {CDM::CLibrary, {"__error"}, 0, 0}}; 5181ad6265SDimitry Andric 5281ad6265SDimitry Andric class ErrnoModeling 5381ad6265SDimitry Andric : public Checker<check::ASTDecl<TranslationUnitDecl>, check::BeginFunction, 5481ad6265SDimitry Andric check::LiveSymbols, eval::Call> { 5581ad6265SDimitry Andric public: 5681ad6265SDimitry Andric void checkASTDecl(const TranslationUnitDecl *D, AnalysisManager &Mgr, 5781ad6265SDimitry Andric BugReporter &BR) const; 5881ad6265SDimitry Andric void checkBeginFunction(CheckerContext &C) const; 5981ad6265SDimitry Andric void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const; 6081ad6265SDimitry Andric bool evalCall(const CallEvent &Call, CheckerContext &C) const; 6181ad6265SDimitry Andric 6281ad6265SDimitry Andric private: 63*0fca6ea1SDimitry Andric // The declaration of an "errno" variable on systems where errno is 64*0fca6ea1SDimitry Andric // represented by a variable (and not a function that queries its location). 65*0fca6ea1SDimitry Andric mutable const VarDecl *ErrnoDecl = nullptr; 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 76*0fca6ea1SDimitry Andric void ErrnoModeling::checkASTDecl(const TranslationUnitDecl *D, 77*0fca6ea1SDimitry Andric AnalysisManager &Mgr, BugReporter &BR) const { 78*0fca6ea1SDimitry Andric // Try to find the declaration of the external variable `int errno;`. 79*0fca6ea1SDimitry Andric // There are also C library implementations, where the `errno` location is 80*0fca6ea1SDimitry Andric // accessed via a function that returns its address; in those environments 81*0fca6ea1SDimitry Andric // this callback has no effect. 82*0fca6ea1SDimitry Andric ASTContext &ACtx = Mgr.getASTContext(); 8381ad6265SDimitry Andric IdentifierInfo &II = ACtx.Idents.get(ErrnoVarName); 8481ad6265SDimitry Andric auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); 8581ad6265SDimitry Andric auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) { 8681ad6265SDimitry Andric if (auto *VD = dyn_cast<VarDecl>(D)) 8781ad6265SDimitry Andric return ACtx.getSourceManager().isInSystemHeader(VD->getLocation()) && 8881ad6265SDimitry Andric VD->hasExternalStorage() && 8981ad6265SDimitry Andric VD->getType().getCanonicalType() == ACtx.IntTy; 9081ad6265SDimitry Andric return false; 9181ad6265SDimitry Andric }); 92*0fca6ea1SDimitry Andric if (Found != LookupRes.end()) 93*0fca6ea1SDimitry Andric ErrnoDecl = cast<VarDecl>(*Found); 9481ad6265SDimitry Andric } 9581ad6265SDimitry Andric 9681ad6265SDimitry Andric void ErrnoModeling::checkBeginFunction(CheckerContext &C) const { 9781ad6265SDimitry Andric if (!C.inTopFrame()) 9881ad6265SDimitry Andric return; 9981ad6265SDimitry Andric 10081ad6265SDimitry Andric ASTContext &ACtx = C.getASTContext(); 10181ad6265SDimitry Andric ProgramStateRef State = C.getState(); 10281ad6265SDimitry Andric 103*0fca6ea1SDimitry Andric const MemRegion *ErrnoR = nullptr; 104*0fca6ea1SDimitry Andric 105*0fca6ea1SDimitry Andric if (ErrnoDecl) { 106*0fca6ea1SDimitry Andric // There is an external 'errno' variable, so we can simply use the memory 107*0fca6ea1SDimitry Andric // region that's associated with it. 108*0fca6ea1SDimitry Andric ErrnoR = State->getRegion(ErrnoDecl, C.getLocationContext()); 10981ad6265SDimitry Andric assert(ErrnoR && "Memory region should exist for the 'errno' variable."); 110*0fca6ea1SDimitry Andric } else { 111*0fca6ea1SDimitry Andric // There is no 'errno' variable, so create a new symbolic memory region 112*0fca6ea1SDimitry Andric // that can be used to model the return value of the "get the location of 113*0fca6ea1SDimitry Andric // errno" internal functions. 114*0fca6ea1SDimitry Andric // NOTE: this `SVal` is created even if errno is not defined or used. 11581ad6265SDimitry Andric SValBuilder &SVB = C.getSValBuilder(); 11681ad6265SDimitry Andric MemRegionManager &RMgr = C.getStateManager().getRegionManager(); 11781ad6265SDimitry Andric 11881ad6265SDimitry Andric const MemSpaceRegion *GlobalSystemSpace = 11981ad6265SDimitry Andric RMgr.getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind); 12081ad6265SDimitry Andric 12181ad6265SDimitry Andric // Create an artifical symbol for the region. 122*0fca6ea1SDimitry Andric // Note that it is not possible to associate a statement or expression in 123*0fca6ea1SDimitry Andric // this case and the `symbolTag` (opaque pointer tag) is just the address 124*0fca6ea1SDimitry Andric // of the data member `ErrnoDecl` of the singleton `ErrnoModeling` checker 125*0fca6ea1SDimitry Andric // object. 12681ad6265SDimitry Andric const SymbolConjured *Sym = SVB.conjureSymbol( 12781ad6265SDimitry Andric nullptr, C.getLocationContext(), 12881ad6265SDimitry Andric ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl); 12981ad6265SDimitry Andric 13081ad6265SDimitry Andric // The symbolic region is untyped, create a typed sub-region in it. 13181ad6265SDimitry Andric // The ElementRegion is used to make the errno region a typed region. 132*0fca6ea1SDimitry Andric ErrnoR = RMgr.getElementRegion( 13381ad6265SDimitry Andric ACtx.IntTy, SVB.makeZeroArrayIndex(), 13481ad6265SDimitry Andric RMgr.getSymbolicRegion(Sym, GlobalSystemSpace), C.getASTContext()); 135*0fca6ea1SDimitry Andric } 136*0fca6ea1SDimitry Andric assert(ErrnoR); 13781ad6265SDimitry Andric State = State->set<ErrnoRegion>(ErrnoR); 13881ad6265SDimitry Andric State = 13981ad6265SDimitry Andric errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant); 14081ad6265SDimitry Andric C.addTransition(State); 14181ad6265SDimitry Andric } 14281ad6265SDimitry Andric 14381ad6265SDimitry Andric bool ErrnoModeling::evalCall(const CallEvent &Call, CheckerContext &C) const { 14481ad6265SDimitry Andric // Return location of "errno" at a call to an "errno address returning" 14581ad6265SDimitry Andric // function. 146*0fca6ea1SDimitry Andric if (errno_modeling::isErrnoLocationCall(Call)) { 14781ad6265SDimitry Andric ProgramStateRef State = C.getState(); 14881ad6265SDimitry Andric 14981ad6265SDimitry Andric const MemRegion *ErrnoR = State->get<ErrnoRegion>(); 15081ad6265SDimitry Andric if (!ErrnoR) 15181ad6265SDimitry Andric return false; 15281ad6265SDimitry Andric 15381ad6265SDimitry Andric State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), 15481ad6265SDimitry Andric loc::MemRegionVal{ErrnoR}); 15581ad6265SDimitry Andric C.addTransition(State); 15681ad6265SDimitry Andric return true; 15781ad6265SDimitry Andric } 15881ad6265SDimitry Andric 15981ad6265SDimitry Andric return false; 16081ad6265SDimitry Andric } 16181ad6265SDimitry Andric 16281ad6265SDimitry Andric void ErrnoModeling::checkLiveSymbols(ProgramStateRef State, 16381ad6265SDimitry Andric SymbolReaper &SR) const { 16481ad6265SDimitry Andric // The special errno region should never garbage collected. 16581ad6265SDimitry Andric if (const auto *ErrnoR = State->get<ErrnoRegion>()) 16681ad6265SDimitry Andric SR.markLive(ErrnoR); 16781ad6265SDimitry Andric } 16881ad6265SDimitry Andric 16981ad6265SDimitry Andric namespace clang { 17081ad6265SDimitry Andric namespace ento { 17181ad6265SDimitry Andric namespace errno_modeling { 17281ad6265SDimitry Andric 173bdd1243dSDimitry Andric std::optional<SVal> getErrnoValue(ProgramStateRef State) { 17481ad6265SDimitry Andric const MemRegion *ErrnoR = State->get<ErrnoRegion>(); 17581ad6265SDimitry Andric if (!ErrnoR) 17681ad6265SDimitry Andric return {}; 17781ad6265SDimitry Andric QualType IntTy = State->getAnalysisManager().getASTContext().IntTy; 17881ad6265SDimitry Andric return State->getSVal(ErrnoR, IntTy); 17981ad6265SDimitry Andric } 18081ad6265SDimitry Andric 18181ad6265SDimitry Andric ProgramStateRef setErrnoValue(ProgramStateRef State, 18281ad6265SDimitry Andric const LocationContext *LCtx, SVal Value, 18381ad6265SDimitry Andric ErrnoCheckState EState) { 18481ad6265SDimitry Andric const MemRegion *ErrnoR = State->get<ErrnoRegion>(); 18581ad6265SDimitry Andric if (!ErrnoR) 18681ad6265SDimitry Andric return State; 18781ad6265SDimitry Andric // First set the errno value, the old state is still available at 'checkBind' 18881ad6265SDimitry Andric // or 'checkLocation' for errno value. 18981ad6265SDimitry Andric State = State->bindLoc(loc::MemRegionVal{ErrnoR}, Value, LCtx); 19081ad6265SDimitry Andric return State->set<ErrnoState>(EState); 19181ad6265SDimitry Andric } 19281ad6265SDimitry Andric 19381ad6265SDimitry Andric ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C, 19481ad6265SDimitry Andric uint64_t Value, ErrnoCheckState EState) { 19581ad6265SDimitry Andric const MemRegion *ErrnoR = State->get<ErrnoRegion>(); 19681ad6265SDimitry Andric if (!ErrnoR) 19781ad6265SDimitry Andric return State; 19881ad6265SDimitry Andric State = State->bindLoc( 19981ad6265SDimitry Andric loc::MemRegionVal{ErrnoR}, 20081ad6265SDimitry Andric C.getSValBuilder().makeIntVal(Value, C.getASTContext().IntTy), 20181ad6265SDimitry Andric C.getLocationContext()); 20281ad6265SDimitry Andric return State->set<ErrnoState>(EState); 20381ad6265SDimitry Andric } 20481ad6265SDimitry Andric 205bdd1243dSDimitry Andric std::optional<Loc> getErrnoLoc(ProgramStateRef State) { 20681ad6265SDimitry Andric const MemRegion *ErrnoR = State->get<ErrnoRegion>(); 20781ad6265SDimitry Andric if (!ErrnoR) 20881ad6265SDimitry Andric return {}; 20981ad6265SDimitry Andric return loc::MemRegionVal{ErrnoR}; 21081ad6265SDimitry Andric } 21181ad6265SDimitry Andric 212bdd1243dSDimitry Andric ErrnoCheckState getErrnoState(ProgramStateRef State) { 213bdd1243dSDimitry Andric return State->get<ErrnoState>(); 214bdd1243dSDimitry Andric } 215bdd1243dSDimitry Andric 21681ad6265SDimitry Andric ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState) { 21781ad6265SDimitry Andric return State->set<ErrnoState>(EState); 21881ad6265SDimitry Andric } 21981ad6265SDimitry Andric 220bdd1243dSDimitry Andric ProgramStateRef clearErrnoState(ProgramStateRef State) { 221bdd1243dSDimitry Andric return setErrnoState(State, Irrelevant); 22281ad6265SDimitry Andric } 22381ad6265SDimitry Andric 224*0fca6ea1SDimitry Andric bool isErrnoLocationCall(const CallEvent &CE) { 225*0fca6ea1SDimitry Andric return ErrnoLocationCalls.contains(CE); 22681ad6265SDimitry Andric } 22781ad6265SDimitry Andric 22881ad6265SDimitry Andric const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message) { 22981ad6265SDimitry Andric return C.getNoteTag([Message](PathSensitiveBugReport &BR) -> std::string { 23081ad6265SDimitry Andric const MemRegion *ErrnoR = BR.getErrorNode()->getState()->get<ErrnoRegion>(); 23181ad6265SDimitry Andric if (ErrnoR && BR.isInteresting(ErrnoR)) { 23281ad6265SDimitry Andric BR.markNotInteresting(ErrnoR); 23381ad6265SDimitry Andric return Message; 23481ad6265SDimitry Andric } 23581ad6265SDimitry Andric return ""; 23681ad6265SDimitry Andric }); 23781ad6265SDimitry Andric } 23881ad6265SDimitry Andric 239bdd1243dSDimitry Andric ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State, 240bdd1243dSDimitry Andric CheckerContext &C) { 241bdd1243dSDimitry Andric return setErrnoState(State, MustNotBeChecked); 242bdd1243dSDimitry Andric } 243bdd1243dSDimitry Andric 244bdd1243dSDimitry Andric ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C, 245bdd1243dSDimitry Andric NonLoc ErrnoSym) { 246bdd1243dSDimitry Andric SValBuilder &SVB = C.getSValBuilder(); 247bdd1243dSDimitry Andric NonLoc ZeroVal = SVB.makeZeroVal(C.getASTContext().IntTy).castAs<NonLoc>(); 248bdd1243dSDimitry Andric DefinedOrUnknownSVal Cond = 249bdd1243dSDimitry Andric SVB.evalBinOp(State, BO_NE, ErrnoSym, ZeroVal, SVB.getConditionType()) 250bdd1243dSDimitry Andric .castAs<DefinedOrUnknownSVal>(); 251bdd1243dSDimitry Andric State = State->assume(Cond, true); 252bdd1243dSDimitry Andric if (!State) 253bdd1243dSDimitry Andric return nullptr; 254bdd1243dSDimitry Andric return setErrnoValue(State, C.getLocationContext(), ErrnoSym, Irrelevant); 255bdd1243dSDimitry Andric } 256bdd1243dSDimitry Andric 257bdd1243dSDimitry Andric ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State, 258bdd1243dSDimitry Andric CheckerContext &C, 259bdd1243dSDimitry Andric const Expr *InvalE) { 260bdd1243dSDimitry Andric const MemRegion *ErrnoR = State->get<ErrnoRegion>(); 261bdd1243dSDimitry Andric if (!ErrnoR) 262bdd1243dSDimitry Andric return State; 263bdd1243dSDimitry Andric State = State->invalidateRegions(ErrnoR, InvalE, C.blockCount(), 264bdd1243dSDimitry Andric C.getLocationContext(), false); 265bdd1243dSDimitry Andric if (!State) 266bdd1243dSDimitry Andric return nullptr; 267bdd1243dSDimitry Andric return setErrnoState(State, MustBeChecked); 268bdd1243dSDimitry Andric } 269bdd1243dSDimitry Andric 27081ad6265SDimitry Andric } // namespace errno_modeling 27181ad6265SDimitry Andric } // namespace ento 27281ad6265SDimitry Andric } // namespace clang 27381ad6265SDimitry Andric 27481ad6265SDimitry Andric void ento::registerErrnoModeling(CheckerManager &mgr) { 27581ad6265SDimitry Andric mgr.registerChecker<ErrnoModeling>(); 27681ad6265SDimitry Andric } 27781ad6265SDimitry Andric 27881ad6265SDimitry Andric bool ento::shouldRegisterErrnoModeling(const CheckerManager &mgr) { 27981ad6265SDimitry Andric return true; 28081ad6265SDimitry Andric } 281