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 void *) 72 73 /// An internal function accessing the errno region. 74 /// Returns null if there isn't any associated memory region. 75 static const MemRegion *getErrnoRegion(ProgramStateRef State) { 76 return reinterpret_cast<const MemRegion *>(State->get<ErrnoRegion>()); 77 } 78 79 /// Search for a variable called "errno" in the AST. 80 /// Return nullptr if not found. 81 static const VarDecl *getErrnoVar(ASTContext &ACtx) { 82 IdentifierInfo &II = ACtx.Idents.get(ErrnoVarName); 83 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); 84 auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) { 85 if (auto *VD = dyn_cast<VarDecl>(D)) 86 return ACtx.getSourceManager().isInSystemHeader(VD->getLocation()) && 87 VD->hasExternalStorage() && 88 VD->getType().getCanonicalType() == ACtx.IntTy; 89 return false; 90 }); 91 if (Found == LookupRes.end()) 92 return nullptr; 93 94 return cast<VarDecl>(*Found); 95 } 96 97 /// Search for a function with a specific name that is used to return a pointer 98 /// to "errno". 99 /// Return nullptr if no such function was found. 100 static const FunctionDecl *getErrnoFunc(ASTContext &ACtx) { 101 SmallVector<const Decl *> LookupRes; 102 for (StringRef ErrnoName : ErrnoLocationFuncNames) { 103 IdentifierInfo &II = ACtx.Idents.get(ErrnoName); 104 llvm::append_range(LookupRes, ACtx.getTranslationUnitDecl()->lookup(&II)); 105 } 106 107 auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) { 108 if (auto *FD = dyn_cast<FunctionDecl>(D)) 109 return ACtx.getSourceManager().isInSystemHeader(FD->getLocation()) && 110 FD->isExternC() && FD->getNumParams() == 0 && 111 FD->getReturnType().getCanonicalType() == 112 ACtx.getPointerType(ACtx.IntTy); 113 return false; 114 }); 115 if (Found == LookupRes.end()) 116 return nullptr; 117 118 return cast<FunctionDecl>(*Found); 119 } 120 121 void ErrnoModeling::checkASTDecl(const TranslationUnitDecl *D, 122 AnalysisManager &Mgr, BugReporter &BR) const { 123 // Try to find an usable `errno` value. 124 // It can be an external variable called "errno" or a function that returns a 125 // pointer to the "errno" value. This function can have different names. 126 // The actual case is dependent on the C library implementation, we 127 // can only search for a match in one of these variations. 128 // We assume that exactly one of these cases might be true. 129 ErrnoDecl = getErrnoVar(Mgr.getASTContext()); 130 if (!ErrnoDecl) 131 ErrnoDecl = getErrnoFunc(Mgr.getASTContext()); 132 } 133 134 void ErrnoModeling::checkBeginFunction(CheckerContext &C) const { 135 if (!C.inTopFrame()) 136 return; 137 138 ASTContext &ACtx = C.getASTContext(); 139 ProgramStateRef State = C.getState(); 140 141 if (const auto *ErrnoVar = dyn_cast_or_null<VarDecl>(ErrnoDecl)) { 142 // There is an external 'errno' variable. 143 // Use its memory region. 144 // The memory region for an 'errno'-like variable is allocated in system 145 // space by MemRegionManager. 146 const MemRegion *ErrnoR = 147 State->getRegion(ErrnoVar, C.getLocationContext()); 148 assert(ErrnoR && "Memory region should exist for the 'errno' variable."); 149 State = State->set<ErrnoRegion>(ErrnoR); 150 State = errno_modeling::setErrnoValue(State, C, 0); 151 C.addTransition(State); 152 } else if (ErrnoDecl) { 153 assert(isa<FunctionDecl>(ErrnoDecl) && "Invalid errno location function."); 154 // There is a function that returns the location of 'errno'. 155 // We must create a memory region for it in system space. 156 // Currently a symbolic region is used with an artifical symbol. 157 // FIXME: It is better to have a custom (new) kind of MemRegion for such 158 // cases. 159 SValBuilder &SVB = C.getSValBuilder(); 160 MemRegionManager &RMgr = C.getStateManager().getRegionManager(); 161 162 const MemSpaceRegion *GlobalSystemSpace = 163 RMgr.getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind); 164 165 // Create an artifical symbol for the region. 166 // It is not possible to associate a statement or expression in this case. 167 const SymbolConjured *Sym = SVB.conjureSymbol( 168 nullptr, C.getLocationContext(), 169 ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl); 170 171 // The symbolic region is untyped, create a typed sub-region in it. 172 // The ElementRegion is used to make the errno region a typed region. 173 const MemRegion *ErrnoR = RMgr.getElementRegion( 174 ACtx.IntTy, SVB.makeZeroArrayIndex(), 175 RMgr.getSymbolicRegion(Sym, GlobalSystemSpace), C.getASTContext()); 176 State = State->set<ErrnoRegion>(ErrnoR); 177 State = errno_modeling::setErrnoValue(State, C, 0); 178 C.addTransition(State); 179 } 180 } 181 182 bool ErrnoModeling::evalCall(const CallEvent &Call, CheckerContext &C) const { 183 // Return location of "errno" at a call to an "errno address returning" 184 // function. 185 if (ErrnoLocationCalls.contains(Call)) { 186 ProgramStateRef State = C.getState(); 187 188 const MemRegion *ErrnoR = getErrnoRegion(State); 189 if (!ErrnoR) 190 return false; 191 192 State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), 193 loc::MemRegionVal{ErrnoR}); 194 C.addTransition(State); 195 return true; 196 } 197 198 return false; 199 } 200 201 void ErrnoModeling::checkLiveSymbols(ProgramStateRef State, 202 SymbolReaper &SR) const { 203 // The special errno region should never garbage collected. 204 if (const auto *ErrnoR = getErrnoRegion(State)) 205 SR.markLive(ErrnoR); 206 } 207 208 namespace clang { 209 namespace ento { 210 namespace errno_modeling { 211 212 Optional<SVal> getErrnoValue(ProgramStateRef State) { 213 const MemRegion *ErrnoR = getErrnoRegion(State); 214 if (!ErrnoR) 215 return {}; 216 QualType IntTy = State->getAnalysisManager().getASTContext().IntTy; 217 return State->getSVal(ErrnoR, IntTy); 218 } 219 220 ProgramStateRef setErrnoValue(ProgramStateRef State, 221 const LocationContext *LCtx, SVal Value) { 222 const MemRegion *ErrnoR = getErrnoRegion(State); 223 if (!ErrnoR) 224 return State; 225 return State->bindLoc(loc::MemRegionVal{ErrnoR}, Value, LCtx); 226 } 227 228 ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C, 229 uint64_t Value) { 230 const MemRegion *ErrnoR = getErrnoRegion(State); 231 if (!ErrnoR) 232 return State; 233 return State->bindLoc( 234 loc::MemRegionVal{ErrnoR}, 235 C.getSValBuilder().makeIntVal(Value, C.getASTContext().IntTy), 236 C.getLocationContext()); 237 } 238 239 } // namespace errno_modeling 240 } // namespace ento 241 } // namespace clang 242 243 void ento::registerErrnoModeling(CheckerManager &mgr) { 244 mgr.registerChecker<ErrnoModeling>(); 245 } 246 247 bool ento::shouldRegisterErrnoModeling(const CheckerManager &mgr) { 248 return true; 249 } 250