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