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 "Errno.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 static const Decl *ErrnoDecl; 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 const Decl *ErrnoModeling::ErrnoDecl = nullptr; 122 123 void ErrnoModeling::checkASTDecl(const TranslationUnitDecl *D, 124 AnalysisManager &Mgr, BugReporter &BR) const { 125 // Try to find an usable `errno` value. 126 // It can be an external variable called "errno" or a function that returns a 127 // pointer to the "errno" value. This function can have different names. 128 // The actual case is dependent on the C library implementation, we 129 // can only search for a match in one of these variations. 130 // We assume that exactly one of these cases might be true. 131 assert(!ErrnoDecl && "Checker should be used for one translation unit."); 132 133 ErrnoDecl = getErrnoVar(Mgr.getASTContext()); 134 if (!ErrnoDecl) 135 ErrnoDecl = getErrnoFunc(Mgr.getASTContext()); 136 } 137 138 void ErrnoModeling::checkBeginFunction(CheckerContext &C) const { 139 if (!C.inTopFrame()) 140 return; 141 142 ASTContext &ACtx = C.getASTContext(); 143 ProgramStateRef State = C.getState(); 144 145 if (const auto *ErrnoVar = dyn_cast_or_null<VarDecl>(ErrnoDecl)) { 146 // There is an external 'errno' variable. 147 // Use its memory region. 148 // The memory region for an 'errno'-like variable is allocated in system 149 // space by MemRegionManager. 150 const MemRegion *ErrnoR = 151 State->getRegion(ErrnoVar, C.getLocationContext()); 152 assert(ErrnoR && "Memory region should exist for the 'errno' variable."); 153 State = State->set<ErrnoRegion>(ErrnoR); 154 State = errno_modeling::setErrnoValue(State, C, 0); 155 C.addTransition(State); 156 } else if (ErrnoDecl) { 157 assert(isa<FunctionDecl>(ErrnoDecl) && "Invalid errno location function."); 158 // There is a function that returns the location of 'errno'. 159 // We must create a memory region for it in system space. 160 // Currently a symbolic region is used with an artifical symbol. 161 // FIXME: It is better to have a custom (new) kind of MemRegion for such 162 // cases. 163 SValBuilder &SVB = C.getSValBuilder(); 164 MemRegionManager &RMgr = C.getStateManager().getRegionManager(); 165 166 const MemSpaceRegion *GlobalSystemSpace = 167 RMgr.getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind); 168 169 // Create an artifical symbol for the region. 170 // It is not possible to associate a statement or expression in this case. 171 const SymbolConjured *Sym = SVB.conjureSymbol( 172 nullptr, C.getLocationContext(), 173 ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl); 174 175 // The symbolic region is untyped, create a typed sub-region in it. 176 // The ElementRegion is used to make the errno region a typed region. 177 const MemRegion *ErrnoR = RMgr.getElementRegion( 178 ACtx.IntTy, SVB.makeZeroArrayIndex(), 179 RMgr.getSymbolicRegion(Sym, GlobalSystemSpace), C.getASTContext()); 180 State = State->set<ErrnoRegion>(ErrnoR); 181 State = errno_modeling::setErrnoValue(State, C, 0); 182 C.addTransition(State); 183 } 184 } 185 186 bool ErrnoModeling::evalCall(const CallEvent &Call, CheckerContext &C) const { 187 // Return location of "errno" at a call to an "errno address returning" 188 // function. 189 if (ErrnoLocationCalls.contains(Call)) { 190 ProgramStateRef State = C.getState(); 191 192 const MemRegion *ErrnoR = getErrnoRegion(State); 193 if (!ErrnoR) 194 return false; 195 196 State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), 197 loc::MemRegionVal{ErrnoR}); 198 C.addTransition(State); 199 return true; 200 } 201 202 return false; 203 } 204 205 void ErrnoModeling::checkLiveSymbols(ProgramStateRef State, 206 SymbolReaper &SR) const { 207 // The special errno region should never garbage collected. 208 if (const auto *ErrnoR = getErrnoRegion(State)) 209 SR.markLive(ErrnoR); 210 } 211 212 namespace clang { 213 namespace ento { 214 namespace errno_modeling { 215 216 Optional<SVal> getErrnoValue(ProgramStateRef State) { 217 const MemRegion *ErrnoR = getErrnoRegion(State); 218 if (!ErrnoR) 219 return {}; 220 QualType IntTy = State->getAnalysisManager().getASTContext().IntTy; 221 return State->getSVal(ErrnoR, IntTy); 222 } 223 224 ProgramStateRef setErrnoValue(ProgramStateRef State, 225 const LocationContext *LCtx, SVal Value) { 226 const MemRegion *ErrnoR = getErrnoRegion(State); 227 if (!ErrnoR) 228 return State; 229 return State->bindLoc(loc::MemRegionVal{ErrnoR}, Value, LCtx); 230 } 231 232 ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C, 233 uint64_t Value) { 234 const MemRegion *ErrnoR = getErrnoRegion(State); 235 if (!ErrnoR) 236 return State; 237 return State->bindLoc( 238 loc::MemRegionVal{ErrnoR}, 239 C.getSValBuilder().makeIntVal(Value, C.getASTContext().IntTy), 240 C.getLocationContext()); 241 } 242 243 } // namespace errno_modeling 244 } // namespace ento 245 } // namespace clang 246 247 void ento::registerErrnoModeling(CheckerManager &mgr) { 248 mgr.registerChecker<ErrnoModeling>(); 249 } 250 251 bool ento::shouldRegisterErrnoModeling(const CheckerManager &mgr) { 252 return true; 253 } 254