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