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 #include <optional> 32 33 using namespace clang; 34 using namespace ento; 35 36 namespace { 37 38 // Name of the "errno" variable. 39 // FIXME: Is there a system where it is not called "errno" but is a variable? 40 const char *ErrnoVarName = "errno"; 41 // Names of functions that return a location of the "errno" value. 42 // FIXME: Are there other similar function names? 43 const char *ErrnoLocationFuncNames[] = {"__errno_location", "___errno", 44 "__errno", "_errno", "__error"}; 45 46 class ErrnoModeling 47 : public Checker<check::ASTDecl<TranslationUnitDecl>, check::BeginFunction, 48 check::LiveSymbols, eval::Call> { 49 public: 50 void checkASTDecl(const TranslationUnitDecl *D, AnalysisManager &Mgr, 51 BugReporter &BR) const; 52 void checkBeginFunction(CheckerContext &C) const; 53 void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const; 54 bool evalCall(const CallEvent &Call, CheckerContext &C) const; 55 56 // The declaration of an "errno" variable or "errno location" function. 57 mutable const Decl *ErrnoDecl = nullptr; 58 59 private: 60 // FIXME: Names from `ErrnoLocationFuncNames` are used to build this set. 61 CallDescriptionSet ErrnoLocationCalls{{{"__errno_location"}, 0, 0}, 62 {{"___errno"}, 0, 0}, 63 {{"__errno"}, 0, 0}, 64 {{"_errno"}, 0, 0}, 65 {{"__error"}, 0, 0}}; 66 }; 67 68 } // namespace 69 70 /// Store a MemRegion that contains the 'errno' integer value. 71 /// The value is null if the 'errno' value was not recognized in the AST. 72 REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoRegion, const MemRegion *) 73 74 REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoState, errno_modeling::ErrnoCheckState) 75 76 /// Search for a variable called "errno" in the AST. 77 /// Return nullptr if not found. 78 static const VarDecl *getErrnoVar(ASTContext &ACtx) { 79 IdentifierInfo &II = ACtx.Idents.get(ErrnoVarName); 80 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); 81 auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) { 82 if (auto *VD = dyn_cast<VarDecl>(D)) 83 return ACtx.getSourceManager().isInSystemHeader(VD->getLocation()) && 84 VD->hasExternalStorage() && 85 VD->getType().getCanonicalType() == ACtx.IntTy; 86 return false; 87 }); 88 if (Found == LookupRes.end()) 89 return nullptr; 90 91 return cast<VarDecl>(*Found); 92 } 93 94 /// Search for a function with a specific name that is used to return a pointer 95 /// to "errno". 96 /// Return nullptr if no such function was found. 97 static const FunctionDecl *getErrnoFunc(ASTContext &ACtx) { 98 SmallVector<const Decl *> LookupRes; 99 for (StringRef ErrnoName : ErrnoLocationFuncNames) { 100 IdentifierInfo &II = ACtx.Idents.get(ErrnoName); 101 llvm::append_range(LookupRes, ACtx.getTranslationUnitDecl()->lookup(&II)); 102 } 103 104 auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) { 105 if (auto *FD = dyn_cast<FunctionDecl>(D)) 106 return ACtx.getSourceManager().isInSystemHeader(FD->getLocation()) && 107 FD->isExternC() && FD->getNumParams() == 0 && 108 FD->getReturnType().getCanonicalType() == 109 ACtx.getPointerType(ACtx.IntTy); 110 return false; 111 }); 112 if (Found == LookupRes.end()) 113 return nullptr; 114 115 return cast<FunctionDecl>(*Found); 116 } 117 118 void ErrnoModeling::checkASTDecl(const TranslationUnitDecl *D, 119 AnalysisManager &Mgr, BugReporter &BR) const { 120 // Try to find an usable `errno` value. 121 // It can be an external variable called "errno" or a function that returns a 122 // pointer to the "errno" value. This function can have different names. 123 // The actual case is dependent on the C library implementation, we 124 // can only search for a match in one of these variations. 125 // We assume that exactly one of these cases might be true. 126 ErrnoDecl = getErrnoVar(Mgr.getASTContext()); 127 if (!ErrnoDecl) 128 ErrnoDecl = getErrnoFunc(Mgr.getASTContext()); 129 } 130 131 void ErrnoModeling::checkBeginFunction(CheckerContext &C) const { 132 if (!C.inTopFrame()) 133 return; 134 135 ASTContext &ACtx = C.getASTContext(); 136 ProgramStateRef State = C.getState(); 137 138 if (const auto *ErrnoVar = dyn_cast_or_null<VarDecl>(ErrnoDecl)) { 139 // There is an external 'errno' variable. 140 // Use its memory region. 141 // The memory region for an 'errno'-like variable is allocated in system 142 // space by MemRegionManager. 143 const MemRegion *ErrnoR = 144 State->getRegion(ErrnoVar, C.getLocationContext()); 145 assert(ErrnoR && "Memory region should exist for the 'errno' variable."); 146 State = State->set<ErrnoRegion>(ErrnoR); 147 State = 148 errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant); 149 C.addTransition(State); 150 } else if (ErrnoDecl) { 151 assert(isa<FunctionDecl>(ErrnoDecl) && "Invalid errno location function."); 152 // There is a function that returns the location of 'errno'. 153 // We must create a memory region for it in system space. 154 // Currently a symbolic region is used with an artifical symbol. 155 // FIXME: It is better to have a custom (new) kind of MemRegion for such 156 // cases. 157 SValBuilder &SVB = C.getSValBuilder(); 158 MemRegionManager &RMgr = C.getStateManager().getRegionManager(); 159 160 const MemSpaceRegion *GlobalSystemSpace = 161 RMgr.getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind); 162 163 // Create an artifical symbol for the region. 164 // It is not possible to associate a statement or expression in this case. 165 const SymbolConjured *Sym = SVB.conjureSymbol( 166 nullptr, C.getLocationContext(), 167 ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl); 168 169 // The symbolic region is untyped, create a typed sub-region in it. 170 // The ElementRegion is used to make the errno region a typed region. 171 const MemRegion *ErrnoR = RMgr.getElementRegion( 172 ACtx.IntTy, SVB.makeZeroArrayIndex(), 173 RMgr.getSymbolicRegion(Sym, GlobalSystemSpace), C.getASTContext()); 174 State = State->set<ErrnoRegion>(ErrnoR); 175 State = 176 errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant); 177 C.addTransition(State); 178 } 179 } 180 181 bool ErrnoModeling::evalCall(const CallEvent &Call, CheckerContext &C) const { 182 // Return location of "errno" at a call to an "errno address returning" 183 // function. 184 if (ErrnoLocationCalls.contains(Call)) { 185 ProgramStateRef State = C.getState(); 186 187 const MemRegion *ErrnoR = State->get<ErrnoRegion>(); 188 if (!ErrnoR) 189 return false; 190 191 State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), 192 loc::MemRegionVal{ErrnoR}); 193 C.addTransition(State); 194 return true; 195 } 196 197 return false; 198 } 199 200 void ErrnoModeling::checkLiveSymbols(ProgramStateRef State, 201 SymbolReaper &SR) const { 202 // The special errno region should never garbage collected. 203 if (const auto *ErrnoR = State->get<ErrnoRegion>()) 204 SR.markLive(ErrnoR); 205 } 206 207 namespace clang { 208 namespace ento { 209 namespace errno_modeling { 210 211 std::optional<SVal> getErrnoValue(ProgramStateRef State) { 212 const MemRegion *ErrnoR = State->get<ErrnoRegion>(); 213 if (!ErrnoR) 214 return {}; 215 QualType IntTy = State->getAnalysisManager().getASTContext().IntTy; 216 return State->getSVal(ErrnoR, IntTy); 217 } 218 219 ProgramStateRef setErrnoValue(ProgramStateRef State, 220 const LocationContext *LCtx, SVal Value, 221 ErrnoCheckState EState) { 222 const MemRegion *ErrnoR = State->get<ErrnoRegion>(); 223 if (!ErrnoR) 224 return State; 225 // First set the errno value, the old state is still available at 'checkBind' 226 // or 'checkLocation' for errno value. 227 State = State->bindLoc(loc::MemRegionVal{ErrnoR}, Value, LCtx); 228 return State->set<ErrnoState>(EState); 229 } 230 231 ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C, 232 uint64_t Value, ErrnoCheckState EState) { 233 const MemRegion *ErrnoR = State->get<ErrnoRegion>(); 234 if (!ErrnoR) 235 return State; 236 State = State->bindLoc( 237 loc::MemRegionVal{ErrnoR}, 238 C.getSValBuilder().makeIntVal(Value, C.getASTContext().IntTy), 239 C.getLocationContext()); 240 return State->set<ErrnoState>(EState); 241 } 242 243 std::optional<Loc> getErrnoLoc(ProgramStateRef State) { 244 const MemRegion *ErrnoR = State->get<ErrnoRegion>(); 245 if (!ErrnoR) 246 return {}; 247 return loc::MemRegionVal{ErrnoR}; 248 } 249 250 ErrnoCheckState getErrnoState(ProgramStateRef State) { 251 return State->get<ErrnoState>(); 252 } 253 254 ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState) { 255 return State->set<ErrnoState>(EState); 256 } 257 258 ProgramStateRef clearErrnoState(ProgramStateRef State) { 259 return setErrnoState(State, Irrelevant); 260 } 261 262 bool isErrno(const Decl *D) { 263 if (const auto *VD = dyn_cast_or_null<VarDecl>(D)) 264 if (const IdentifierInfo *II = VD->getIdentifier()) 265 return II->getName() == ErrnoVarName; 266 if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) 267 if (const IdentifierInfo *II = FD->getIdentifier()) 268 return llvm::is_contained(ErrnoLocationFuncNames, II->getName()); 269 return false; 270 } 271 272 const char *describeErrnoCheckState(ErrnoCheckState CS) { 273 assert(CS == errno_modeling::MustNotBeChecked && 274 "Errno description not applicable."); 275 return "may be undefined after the call and should not be used"; 276 } 277 278 const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message) { 279 return C.getNoteTag([Message](PathSensitiveBugReport &BR) -> std::string { 280 const MemRegion *ErrnoR = BR.getErrorNode()->getState()->get<ErrnoRegion>(); 281 if (ErrnoR && BR.isInteresting(ErrnoR)) { 282 BR.markNotInteresting(ErrnoR); 283 return Message; 284 } 285 return ""; 286 }); 287 } 288 289 ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State, 290 CheckerContext &C) { 291 return setErrnoState(State, MustNotBeChecked); 292 } 293 294 ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C, 295 NonLoc ErrnoSym) { 296 SValBuilder &SVB = C.getSValBuilder(); 297 NonLoc ZeroVal = SVB.makeZeroVal(C.getASTContext().IntTy).castAs<NonLoc>(); 298 DefinedOrUnknownSVal Cond = 299 SVB.evalBinOp(State, BO_NE, ErrnoSym, ZeroVal, SVB.getConditionType()) 300 .castAs<DefinedOrUnknownSVal>(); 301 State = State->assume(Cond, true); 302 if (!State) 303 return nullptr; 304 return setErrnoValue(State, C.getLocationContext(), ErrnoSym, Irrelevant); 305 } 306 307 ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State, 308 CheckerContext &C, 309 const Expr *InvalE) { 310 const MemRegion *ErrnoR = State->get<ErrnoRegion>(); 311 if (!ErrnoR) 312 return State; 313 State = State->invalidateRegions(ErrnoR, InvalE, C.blockCount(), 314 C.getLocationContext(), false); 315 if (!State) 316 return nullptr; 317 return setErrnoState(State, MustBeChecked); 318 } 319 320 const NoteTag *getNoteTagForStdSuccess(CheckerContext &C, llvm::StringRef Fn) { 321 return getErrnoNoteTag( 322 C, (Twine("Assuming that function '") + Twine(Fn) + 323 Twine("' is successful, in this case the value 'errno' ") + 324 Twine(describeErrnoCheckState(MustNotBeChecked))) 325 .str()); 326 } 327 328 const NoteTag *getNoteTagForStdMustBeChecked(CheckerContext &C, 329 llvm::StringRef Fn) { 330 return getErrnoNoteTag( 331 C, (Twine("Function '") + Twine(Fn) + 332 Twine("' indicates failure only by setting of 'errno'")) 333 .str()); 334 } 335 336 } // namespace errno_modeling 337 } // namespace ento 338 } // namespace clang 339 340 void ento::registerErrnoModeling(CheckerManager &mgr) { 341 mgr.registerChecker<ErrnoModeling>(); 342 } 343 344 bool ento::shouldRegisterErrnoModeling(const CheckerManager &mgr) { 345 return true; 346 } 347