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