1*81ad6265SDimitry Andric //=== ErrnoModeling.cpp -----------------------------------------*- C++ -*-===// 2*81ad6265SDimitry Andric // 3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*81ad6265SDimitry Andric // 7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 8*81ad6265SDimitry Andric // 9*81ad6265SDimitry Andric // This defines a checker `ErrnoModeling`, which is used to make the system 10*81ad6265SDimitry Andric // value 'errno' available to other checkers. 11*81ad6265SDimitry Andric // The 'errno' value is stored at a special memory region that is accessible 12*81ad6265SDimitry Andric // through the `errno_modeling` namespace. The memory region is either the 13*81ad6265SDimitry Andric // region of `errno` itself if it is a variable, otherwise an artifically 14*81ad6265SDimitry Andric // created region (in the system memory space). If `errno` is defined by using 15*81ad6265SDimitry Andric // a function which returns the address of it (this is always the case if it is 16*81ad6265SDimitry Andric // not a variable) this function is recognized and evaluated. In this way 17*81ad6265SDimitry Andric // `errno` becomes visible to the analysis and checkers can change its value. 18*81ad6265SDimitry Andric // 19*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 20*81ad6265SDimitry Andric 21*81ad6265SDimitry Andric #include "ErrnoModeling.h" 22*81ad6265SDimitry Andric #include "clang/AST/ParentMapContext.h" 23*81ad6265SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 24*81ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 25*81ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h" 26*81ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" 27*81ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 28*81ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 29*81ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 30*81ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h" 31*81ad6265SDimitry Andric 32*81ad6265SDimitry Andric using namespace clang; 33*81ad6265SDimitry Andric using namespace ento; 34*81ad6265SDimitry Andric 35*81ad6265SDimitry Andric namespace { 36*81ad6265SDimitry Andric 37*81ad6265SDimitry Andric // Name of the "errno" variable. 38*81ad6265SDimitry Andric // FIXME: Is there a system where it is not called "errno" but is a variable? 39*81ad6265SDimitry Andric const char *ErrnoVarName = "errno"; 40*81ad6265SDimitry Andric // Names of functions that return a location of the "errno" value. 41*81ad6265SDimitry Andric // FIXME: Are there other similar function names? 42*81ad6265SDimitry Andric const char *ErrnoLocationFuncNames[] = {"__errno_location", "___errno", 43*81ad6265SDimitry Andric "__errno", "_errno", "__error"}; 44*81ad6265SDimitry Andric 45*81ad6265SDimitry Andric class ErrnoModeling 46*81ad6265SDimitry Andric : public Checker<check::ASTDecl<TranslationUnitDecl>, check::BeginFunction, 47*81ad6265SDimitry Andric check::LiveSymbols, eval::Call> { 48*81ad6265SDimitry Andric public: 49*81ad6265SDimitry Andric void checkASTDecl(const TranslationUnitDecl *D, AnalysisManager &Mgr, 50*81ad6265SDimitry Andric BugReporter &BR) const; 51*81ad6265SDimitry Andric void checkBeginFunction(CheckerContext &C) const; 52*81ad6265SDimitry Andric void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const; 53*81ad6265SDimitry Andric bool evalCall(const CallEvent &Call, CheckerContext &C) const; 54*81ad6265SDimitry Andric 55*81ad6265SDimitry Andric // The declaration of an "errno" variable or "errno location" function. 56*81ad6265SDimitry Andric mutable const Decl *ErrnoDecl = nullptr; 57*81ad6265SDimitry Andric 58*81ad6265SDimitry Andric private: 59*81ad6265SDimitry Andric // FIXME: Names from `ErrnoLocationFuncNames` are used to build this set. 60*81ad6265SDimitry Andric CallDescriptionSet ErrnoLocationCalls{{"__errno_location", 0, 0}, 61*81ad6265SDimitry Andric {"___errno", 0, 0}, 62*81ad6265SDimitry Andric {"__errno", 0, 0}, 63*81ad6265SDimitry Andric {"_errno", 0, 0}, 64*81ad6265SDimitry Andric {"__error", 0, 0}}; 65*81ad6265SDimitry Andric }; 66*81ad6265SDimitry Andric 67*81ad6265SDimitry Andric } // namespace 68*81ad6265SDimitry Andric 69*81ad6265SDimitry Andric /// Store a MemRegion that contains the 'errno' integer value. 70*81ad6265SDimitry Andric /// The value is null if the 'errno' value was not recognized in the AST. 71*81ad6265SDimitry Andric REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoRegion, const MemRegion *) 72*81ad6265SDimitry Andric 73*81ad6265SDimitry Andric REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoState, errno_modeling::ErrnoCheckState) 74*81ad6265SDimitry Andric 75*81ad6265SDimitry Andric /// Search for a variable called "errno" in the AST. 76*81ad6265SDimitry Andric /// Return nullptr if not found. 77*81ad6265SDimitry Andric static const VarDecl *getErrnoVar(ASTContext &ACtx) { 78*81ad6265SDimitry Andric IdentifierInfo &II = ACtx.Idents.get(ErrnoVarName); 79*81ad6265SDimitry Andric auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); 80*81ad6265SDimitry Andric auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) { 81*81ad6265SDimitry Andric if (auto *VD = dyn_cast<VarDecl>(D)) 82*81ad6265SDimitry Andric return ACtx.getSourceManager().isInSystemHeader(VD->getLocation()) && 83*81ad6265SDimitry Andric VD->hasExternalStorage() && 84*81ad6265SDimitry Andric VD->getType().getCanonicalType() == ACtx.IntTy; 85*81ad6265SDimitry Andric return false; 86*81ad6265SDimitry Andric }); 87*81ad6265SDimitry Andric if (Found == LookupRes.end()) 88*81ad6265SDimitry Andric return nullptr; 89*81ad6265SDimitry Andric 90*81ad6265SDimitry Andric return cast<VarDecl>(*Found); 91*81ad6265SDimitry Andric } 92*81ad6265SDimitry Andric 93*81ad6265SDimitry Andric /// Search for a function with a specific name that is used to return a pointer 94*81ad6265SDimitry Andric /// to "errno". 95*81ad6265SDimitry Andric /// Return nullptr if no such function was found. 96*81ad6265SDimitry Andric static const FunctionDecl *getErrnoFunc(ASTContext &ACtx) { 97*81ad6265SDimitry Andric SmallVector<const Decl *> LookupRes; 98*81ad6265SDimitry Andric for (StringRef ErrnoName : ErrnoLocationFuncNames) { 99*81ad6265SDimitry Andric IdentifierInfo &II = ACtx.Idents.get(ErrnoName); 100*81ad6265SDimitry Andric llvm::append_range(LookupRes, ACtx.getTranslationUnitDecl()->lookup(&II)); 101*81ad6265SDimitry Andric } 102*81ad6265SDimitry Andric 103*81ad6265SDimitry Andric auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) { 104*81ad6265SDimitry Andric if (auto *FD = dyn_cast<FunctionDecl>(D)) 105*81ad6265SDimitry Andric return ACtx.getSourceManager().isInSystemHeader(FD->getLocation()) && 106*81ad6265SDimitry Andric FD->isExternC() && FD->getNumParams() == 0 && 107*81ad6265SDimitry Andric FD->getReturnType().getCanonicalType() == 108*81ad6265SDimitry Andric ACtx.getPointerType(ACtx.IntTy); 109*81ad6265SDimitry Andric return false; 110*81ad6265SDimitry Andric }); 111*81ad6265SDimitry Andric if (Found == LookupRes.end()) 112*81ad6265SDimitry Andric return nullptr; 113*81ad6265SDimitry Andric 114*81ad6265SDimitry Andric return cast<FunctionDecl>(*Found); 115*81ad6265SDimitry Andric } 116*81ad6265SDimitry Andric 117*81ad6265SDimitry Andric void ErrnoModeling::checkASTDecl(const TranslationUnitDecl *D, 118*81ad6265SDimitry Andric AnalysisManager &Mgr, BugReporter &BR) const { 119*81ad6265SDimitry Andric // Try to find an usable `errno` value. 120*81ad6265SDimitry Andric // It can be an external variable called "errno" or a function that returns a 121*81ad6265SDimitry Andric // pointer to the "errno" value. This function can have different names. 122*81ad6265SDimitry Andric // The actual case is dependent on the C library implementation, we 123*81ad6265SDimitry Andric // can only search for a match in one of these variations. 124*81ad6265SDimitry Andric // We assume that exactly one of these cases might be true. 125*81ad6265SDimitry Andric ErrnoDecl = getErrnoVar(Mgr.getASTContext()); 126*81ad6265SDimitry Andric if (!ErrnoDecl) 127*81ad6265SDimitry Andric ErrnoDecl = getErrnoFunc(Mgr.getASTContext()); 128*81ad6265SDimitry Andric } 129*81ad6265SDimitry Andric 130*81ad6265SDimitry Andric void ErrnoModeling::checkBeginFunction(CheckerContext &C) const { 131*81ad6265SDimitry Andric if (!C.inTopFrame()) 132*81ad6265SDimitry Andric return; 133*81ad6265SDimitry Andric 134*81ad6265SDimitry Andric ASTContext &ACtx = C.getASTContext(); 135*81ad6265SDimitry Andric ProgramStateRef State = C.getState(); 136*81ad6265SDimitry Andric 137*81ad6265SDimitry Andric if (const auto *ErrnoVar = dyn_cast_or_null<VarDecl>(ErrnoDecl)) { 138*81ad6265SDimitry Andric // There is an external 'errno' variable. 139*81ad6265SDimitry Andric // Use its memory region. 140*81ad6265SDimitry Andric // The memory region for an 'errno'-like variable is allocated in system 141*81ad6265SDimitry Andric // space by MemRegionManager. 142*81ad6265SDimitry Andric const MemRegion *ErrnoR = 143*81ad6265SDimitry Andric State->getRegion(ErrnoVar, C.getLocationContext()); 144*81ad6265SDimitry Andric assert(ErrnoR && "Memory region should exist for the 'errno' variable."); 145*81ad6265SDimitry Andric State = State->set<ErrnoRegion>(ErrnoR); 146*81ad6265SDimitry Andric State = 147*81ad6265SDimitry Andric errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant); 148*81ad6265SDimitry Andric C.addTransition(State); 149*81ad6265SDimitry Andric } else if (ErrnoDecl) { 150*81ad6265SDimitry Andric assert(isa<FunctionDecl>(ErrnoDecl) && "Invalid errno location function."); 151*81ad6265SDimitry Andric // There is a function that returns the location of 'errno'. 152*81ad6265SDimitry Andric // We must create a memory region for it in system space. 153*81ad6265SDimitry Andric // Currently a symbolic region is used with an artifical symbol. 154*81ad6265SDimitry Andric // FIXME: It is better to have a custom (new) kind of MemRegion for such 155*81ad6265SDimitry Andric // cases. 156*81ad6265SDimitry Andric SValBuilder &SVB = C.getSValBuilder(); 157*81ad6265SDimitry Andric MemRegionManager &RMgr = C.getStateManager().getRegionManager(); 158*81ad6265SDimitry Andric 159*81ad6265SDimitry Andric const MemSpaceRegion *GlobalSystemSpace = 160*81ad6265SDimitry Andric RMgr.getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind); 161*81ad6265SDimitry Andric 162*81ad6265SDimitry Andric // Create an artifical symbol for the region. 163*81ad6265SDimitry Andric // It is not possible to associate a statement or expression in this case. 164*81ad6265SDimitry Andric const SymbolConjured *Sym = SVB.conjureSymbol( 165*81ad6265SDimitry Andric nullptr, C.getLocationContext(), 166*81ad6265SDimitry Andric ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl); 167*81ad6265SDimitry Andric 168*81ad6265SDimitry Andric // The symbolic region is untyped, create a typed sub-region in it. 169*81ad6265SDimitry Andric // The ElementRegion is used to make the errno region a typed region. 170*81ad6265SDimitry Andric const MemRegion *ErrnoR = RMgr.getElementRegion( 171*81ad6265SDimitry Andric ACtx.IntTy, SVB.makeZeroArrayIndex(), 172*81ad6265SDimitry Andric RMgr.getSymbolicRegion(Sym, GlobalSystemSpace), C.getASTContext()); 173*81ad6265SDimitry Andric State = State->set<ErrnoRegion>(ErrnoR); 174*81ad6265SDimitry Andric State = 175*81ad6265SDimitry Andric errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant); 176*81ad6265SDimitry Andric C.addTransition(State); 177*81ad6265SDimitry Andric } 178*81ad6265SDimitry Andric } 179*81ad6265SDimitry Andric 180*81ad6265SDimitry Andric bool ErrnoModeling::evalCall(const CallEvent &Call, CheckerContext &C) const { 181*81ad6265SDimitry Andric // Return location of "errno" at a call to an "errno address returning" 182*81ad6265SDimitry Andric // function. 183*81ad6265SDimitry Andric if (ErrnoLocationCalls.contains(Call)) { 184*81ad6265SDimitry Andric ProgramStateRef State = C.getState(); 185*81ad6265SDimitry Andric 186*81ad6265SDimitry Andric const MemRegion *ErrnoR = State->get<ErrnoRegion>(); 187*81ad6265SDimitry Andric if (!ErrnoR) 188*81ad6265SDimitry Andric return false; 189*81ad6265SDimitry Andric 190*81ad6265SDimitry Andric State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), 191*81ad6265SDimitry Andric loc::MemRegionVal{ErrnoR}); 192*81ad6265SDimitry Andric C.addTransition(State); 193*81ad6265SDimitry Andric return true; 194*81ad6265SDimitry Andric } 195*81ad6265SDimitry Andric 196*81ad6265SDimitry Andric return false; 197*81ad6265SDimitry Andric } 198*81ad6265SDimitry Andric 199*81ad6265SDimitry Andric void ErrnoModeling::checkLiveSymbols(ProgramStateRef State, 200*81ad6265SDimitry Andric SymbolReaper &SR) const { 201*81ad6265SDimitry Andric // The special errno region should never garbage collected. 202*81ad6265SDimitry Andric if (const auto *ErrnoR = State->get<ErrnoRegion>()) 203*81ad6265SDimitry Andric SR.markLive(ErrnoR); 204*81ad6265SDimitry Andric } 205*81ad6265SDimitry Andric 206*81ad6265SDimitry Andric namespace clang { 207*81ad6265SDimitry Andric namespace ento { 208*81ad6265SDimitry Andric namespace errno_modeling { 209*81ad6265SDimitry Andric 210*81ad6265SDimitry Andric Optional<SVal> getErrnoValue(ProgramStateRef State) { 211*81ad6265SDimitry Andric const MemRegion *ErrnoR = State->get<ErrnoRegion>(); 212*81ad6265SDimitry Andric if (!ErrnoR) 213*81ad6265SDimitry Andric return {}; 214*81ad6265SDimitry Andric QualType IntTy = State->getAnalysisManager().getASTContext().IntTy; 215*81ad6265SDimitry Andric return State->getSVal(ErrnoR, IntTy); 216*81ad6265SDimitry Andric } 217*81ad6265SDimitry Andric 218*81ad6265SDimitry Andric ProgramStateRef setErrnoValue(ProgramStateRef State, 219*81ad6265SDimitry Andric const LocationContext *LCtx, SVal Value, 220*81ad6265SDimitry Andric ErrnoCheckState EState) { 221*81ad6265SDimitry Andric const MemRegion *ErrnoR = State->get<ErrnoRegion>(); 222*81ad6265SDimitry Andric if (!ErrnoR) 223*81ad6265SDimitry Andric return State; 224*81ad6265SDimitry Andric // First set the errno value, the old state is still available at 'checkBind' 225*81ad6265SDimitry Andric // or 'checkLocation' for errno value. 226*81ad6265SDimitry Andric State = State->bindLoc(loc::MemRegionVal{ErrnoR}, Value, LCtx); 227*81ad6265SDimitry Andric return State->set<ErrnoState>(EState); 228*81ad6265SDimitry Andric } 229*81ad6265SDimitry Andric 230*81ad6265SDimitry Andric ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C, 231*81ad6265SDimitry Andric uint64_t Value, ErrnoCheckState EState) { 232*81ad6265SDimitry Andric const MemRegion *ErrnoR = State->get<ErrnoRegion>(); 233*81ad6265SDimitry Andric if (!ErrnoR) 234*81ad6265SDimitry Andric return State; 235*81ad6265SDimitry Andric State = State->bindLoc( 236*81ad6265SDimitry Andric loc::MemRegionVal{ErrnoR}, 237*81ad6265SDimitry Andric C.getSValBuilder().makeIntVal(Value, C.getASTContext().IntTy), 238*81ad6265SDimitry Andric C.getLocationContext()); 239*81ad6265SDimitry Andric return State->set<ErrnoState>(EState); 240*81ad6265SDimitry Andric } 241*81ad6265SDimitry Andric 242*81ad6265SDimitry Andric Optional<Loc> getErrnoLoc(ProgramStateRef State) { 243*81ad6265SDimitry Andric const MemRegion *ErrnoR = State->get<ErrnoRegion>(); 244*81ad6265SDimitry Andric if (!ErrnoR) 245*81ad6265SDimitry Andric return {}; 246*81ad6265SDimitry Andric return loc::MemRegionVal{ErrnoR}; 247*81ad6265SDimitry Andric } 248*81ad6265SDimitry Andric 249*81ad6265SDimitry Andric ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState) { 250*81ad6265SDimitry Andric return State->set<ErrnoState>(EState); 251*81ad6265SDimitry Andric } 252*81ad6265SDimitry Andric 253*81ad6265SDimitry Andric ErrnoCheckState getErrnoState(ProgramStateRef State) { 254*81ad6265SDimitry Andric return State->get<ErrnoState>(); 255*81ad6265SDimitry Andric } 256*81ad6265SDimitry Andric 257*81ad6265SDimitry Andric bool isErrno(const Decl *D) { 258*81ad6265SDimitry Andric if (const auto *VD = dyn_cast_or_null<VarDecl>(D)) 259*81ad6265SDimitry Andric if (const IdentifierInfo *II = VD->getIdentifier()) 260*81ad6265SDimitry Andric return II->getName() == ErrnoVarName; 261*81ad6265SDimitry Andric if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) 262*81ad6265SDimitry Andric if (const IdentifierInfo *II = FD->getIdentifier()) 263*81ad6265SDimitry Andric return llvm::is_contained(ErrnoLocationFuncNames, II->getName()); 264*81ad6265SDimitry Andric return false; 265*81ad6265SDimitry Andric } 266*81ad6265SDimitry Andric 267*81ad6265SDimitry Andric const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message) { 268*81ad6265SDimitry Andric return C.getNoteTag([Message](PathSensitiveBugReport &BR) -> std::string { 269*81ad6265SDimitry Andric const MemRegion *ErrnoR = BR.getErrorNode()->getState()->get<ErrnoRegion>(); 270*81ad6265SDimitry Andric if (ErrnoR && BR.isInteresting(ErrnoR)) { 271*81ad6265SDimitry Andric BR.markNotInteresting(ErrnoR); 272*81ad6265SDimitry Andric return Message; 273*81ad6265SDimitry Andric } 274*81ad6265SDimitry Andric return ""; 275*81ad6265SDimitry Andric }); 276*81ad6265SDimitry Andric } 277*81ad6265SDimitry Andric 278*81ad6265SDimitry Andric } // namespace errno_modeling 279*81ad6265SDimitry Andric } // namespace ento 280*81ad6265SDimitry Andric } // namespace clang 281*81ad6265SDimitry Andric 282*81ad6265SDimitry Andric void ento::registerErrnoModeling(CheckerManager &mgr) { 283*81ad6265SDimitry Andric mgr.registerChecker<ErrnoModeling>(); 284*81ad6265SDimitry Andric } 285*81ad6265SDimitry Andric 286*81ad6265SDimitry Andric bool ento::shouldRegisterErrnoModeling(const CheckerManager &mgr) { 287*81ad6265SDimitry Andric return true; 288*81ad6265SDimitry Andric } 289