1*81ad6265SDimitry Andric //=== ErrnoChecker.cpp ------------------------------------------*- C++ -*-===// 2*81ad6265SDimitry Andric // 3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*81ad6265SDimitry Andric // 7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 8*81ad6265SDimitry Andric // 9*81ad6265SDimitry Andric // This defines an "errno checker" that can detect some invalid use of the 10*81ad6265SDimitry Andric // system-defined value 'errno'. This checker works together with the 11*81ad6265SDimitry Andric // ErrnoModeling checker and other checkers like StdCLibraryFunctions. 12*81ad6265SDimitry Andric // 13*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 14*81ad6265SDimitry Andric 15*81ad6265SDimitry Andric #include "ErrnoModeling.h" 16*81ad6265SDimitry Andric #include "clang/AST/ParentMapContext.h" 17*81ad6265SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 18*81ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 19*81ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h" 20*81ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" 21*81ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 22*81ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 23*81ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 24*81ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h" 25*81ad6265SDimitry Andric 26*81ad6265SDimitry Andric using namespace clang; 27*81ad6265SDimitry Andric using namespace ento; 28*81ad6265SDimitry Andric using namespace errno_modeling; 29*81ad6265SDimitry Andric 30*81ad6265SDimitry Andric namespace { 31*81ad6265SDimitry Andric 32*81ad6265SDimitry Andric class ErrnoChecker 33*81ad6265SDimitry Andric : public Checker<check::Location, check::PreCall, check::RegionChanges> { 34*81ad6265SDimitry Andric public: 35*81ad6265SDimitry Andric void checkLocation(SVal Loc, bool IsLoad, const Stmt *S, 36*81ad6265SDimitry Andric CheckerContext &) const; 37*81ad6265SDimitry Andric void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 38*81ad6265SDimitry Andric ProgramStateRef 39*81ad6265SDimitry Andric checkRegionChanges(ProgramStateRef State, 40*81ad6265SDimitry Andric const InvalidatedSymbols *Invalidated, 41*81ad6265SDimitry Andric ArrayRef<const MemRegion *> ExplicitRegions, 42*81ad6265SDimitry Andric ArrayRef<const MemRegion *> Regions, 43*81ad6265SDimitry Andric const LocationContext *LCtx, const CallEvent *Call) const; 44*81ad6265SDimitry Andric void checkBranchCondition(const Stmt *Condition, CheckerContext &Ctx) const; 45*81ad6265SDimitry Andric 46*81ad6265SDimitry Andric /// Indicates if a read (load) of \c errno is allowed in a non-condition part 47*81ad6265SDimitry Andric /// of \c if, \c switch, loop and conditional statements when the errno 48*81ad6265SDimitry Andric /// value may be undefined. 49*81ad6265SDimitry Andric bool AllowErrnoReadOutsideConditions = true; 50*81ad6265SDimitry Andric 51*81ad6265SDimitry Andric private: 52*81ad6265SDimitry Andric void generateErrnoNotCheckedBug(CheckerContext &C, ProgramStateRef State, 53*81ad6265SDimitry Andric const MemRegion *ErrnoRegion, 54*81ad6265SDimitry Andric const CallEvent *CallMayChangeErrno) const; 55*81ad6265SDimitry Andric 56*81ad6265SDimitry Andric BugType BT_InvalidErrnoRead{this, "Value of 'errno' could be undefined", 57*81ad6265SDimitry Andric "Error handling"}; 58*81ad6265SDimitry Andric BugType BT_ErrnoNotChecked{this, "Value of 'errno' was not checked", 59*81ad6265SDimitry Andric "Error handling"}; 60*81ad6265SDimitry Andric }; 61*81ad6265SDimitry Andric 62*81ad6265SDimitry Andric } // namespace 63*81ad6265SDimitry Andric 64*81ad6265SDimitry Andric static ProgramStateRef setErrnoStateIrrelevant(ProgramStateRef State) { 65*81ad6265SDimitry Andric return setErrnoState(State, Irrelevant); 66*81ad6265SDimitry Andric } 67*81ad6265SDimitry Andric 68*81ad6265SDimitry Andric /// Check if a statement (expression) or an ancestor of it is in a condition 69*81ad6265SDimitry Andric /// part of a (conditional, loop, switch) statement. 70*81ad6265SDimitry Andric static bool isInCondition(const Stmt *S, CheckerContext &C) { 71*81ad6265SDimitry Andric ParentMapContext &ParentCtx = C.getASTContext().getParentMapContext(); 72*81ad6265SDimitry Andric bool CondFound = false; 73*81ad6265SDimitry Andric while (S && !CondFound) { 74*81ad6265SDimitry Andric const DynTypedNodeList Parents = ParentCtx.getParents(*S); 75*81ad6265SDimitry Andric if (Parents.empty()) 76*81ad6265SDimitry Andric break; 77*81ad6265SDimitry Andric const auto *ParentS = Parents[0].get<Stmt>(); 78*81ad6265SDimitry Andric if (!ParentS || isa<CallExpr>(ParentS)) 79*81ad6265SDimitry Andric break; 80*81ad6265SDimitry Andric switch (ParentS->getStmtClass()) { 81*81ad6265SDimitry Andric case Expr::IfStmtClass: 82*81ad6265SDimitry Andric CondFound = (S == cast<IfStmt>(ParentS)->getCond()); 83*81ad6265SDimitry Andric break; 84*81ad6265SDimitry Andric case Expr::ForStmtClass: 85*81ad6265SDimitry Andric CondFound = (S == cast<ForStmt>(ParentS)->getCond()); 86*81ad6265SDimitry Andric break; 87*81ad6265SDimitry Andric case Expr::DoStmtClass: 88*81ad6265SDimitry Andric CondFound = (S == cast<DoStmt>(ParentS)->getCond()); 89*81ad6265SDimitry Andric break; 90*81ad6265SDimitry Andric case Expr::WhileStmtClass: 91*81ad6265SDimitry Andric CondFound = (S == cast<WhileStmt>(ParentS)->getCond()); 92*81ad6265SDimitry Andric break; 93*81ad6265SDimitry Andric case Expr::SwitchStmtClass: 94*81ad6265SDimitry Andric CondFound = (S == cast<SwitchStmt>(ParentS)->getCond()); 95*81ad6265SDimitry Andric break; 96*81ad6265SDimitry Andric case Expr::ConditionalOperatorClass: 97*81ad6265SDimitry Andric CondFound = (S == cast<ConditionalOperator>(ParentS)->getCond()); 98*81ad6265SDimitry Andric break; 99*81ad6265SDimitry Andric case Expr::BinaryConditionalOperatorClass: 100*81ad6265SDimitry Andric CondFound = (S == cast<BinaryConditionalOperator>(ParentS)->getCommon()); 101*81ad6265SDimitry Andric break; 102*81ad6265SDimitry Andric default: 103*81ad6265SDimitry Andric break; 104*81ad6265SDimitry Andric } 105*81ad6265SDimitry Andric S = ParentS; 106*81ad6265SDimitry Andric } 107*81ad6265SDimitry Andric return CondFound; 108*81ad6265SDimitry Andric } 109*81ad6265SDimitry Andric 110*81ad6265SDimitry Andric void ErrnoChecker::generateErrnoNotCheckedBug( 111*81ad6265SDimitry Andric CheckerContext &C, ProgramStateRef State, const MemRegion *ErrnoRegion, 112*81ad6265SDimitry Andric const CallEvent *CallMayChangeErrno) const { 113*81ad6265SDimitry Andric if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) { 114*81ad6265SDimitry Andric SmallString<100> StrBuf; 115*81ad6265SDimitry Andric llvm::raw_svector_ostream OS(StrBuf); 116*81ad6265SDimitry Andric if (CallMayChangeErrno) { 117*81ad6265SDimitry Andric OS << "Value of 'errno' was not checked and may be overwritten by " 118*81ad6265SDimitry Andric "function '"; 119*81ad6265SDimitry Andric const auto *CallD = 120*81ad6265SDimitry Andric dyn_cast_or_null<FunctionDecl>(CallMayChangeErrno->getDecl()); 121*81ad6265SDimitry Andric assert(CallD && CallD->getIdentifier()); 122*81ad6265SDimitry Andric OS << CallD->getIdentifier()->getName() << "'"; 123*81ad6265SDimitry Andric } else { 124*81ad6265SDimitry Andric OS << "Value of 'errno' was not checked and is overwritten here"; 125*81ad6265SDimitry Andric } 126*81ad6265SDimitry Andric auto BR = std::make_unique<PathSensitiveBugReport>(BT_ErrnoNotChecked, 127*81ad6265SDimitry Andric OS.str(), N); 128*81ad6265SDimitry Andric BR->markInteresting(ErrnoRegion); 129*81ad6265SDimitry Andric C.emitReport(std::move(BR)); 130*81ad6265SDimitry Andric } 131*81ad6265SDimitry Andric } 132*81ad6265SDimitry Andric 133*81ad6265SDimitry Andric void ErrnoChecker::checkLocation(SVal Loc, bool IsLoad, const Stmt *S, 134*81ad6265SDimitry Andric CheckerContext &C) const { 135*81ad6265SDimitry Andric Optional<ento::Loc> ErrnoLoc = getErrnoLoc(C.getState()); 136*81ad6265SDimitry Andric if (!ErrnoLoc) 137*81ad6265SDimitry Andric return; 138*81ad6265SDimitry Andric 139*81ad6265SDimitry Andric auto L = Loc.getAs<ento::Loc>(); 140*81ad6265SDimitry Andric if (!L || *ErrnoLoc != *L) 141*81ad6265SDimitry Andric return; 142*81ad6265SDimitry Andric 143*81ad6265SDimitry Andric ProgramStateRef State = C.getState(); 144*81ad6265SDimitry Andric ErrnoCheckState EState = getErrnoState(State); 145*81ad6265SDimitry Andric 146*81ad6265SDimitry Andric if (IsLoad) { 147*81ad6265SDimitry Andric switch (EState) { 148*81ad6265SDimitry Andric case MustNotBeChecked: 149*81ad6265SDimitry Andric // Read of 'errno' when it may have undefined value. 150*81ad6265SDimitry Andric if (!AllowErrnoReadOutsideConditions || isInCondition(S, C)) { 151*81ad6265SDimitry Andric if (ExplodedNode *N = C.generateErrorNode()) { 152*81ad6265SDimitry Andric auto BR = std::make_unique<PathSensitiveBugReport>( 153*81ad6265SDimitry Andric BT_InvalidErrnoRead, 154*81ad6265SDimitry Andric "An undefined value may be read from 'errno'", N); 155*81ad6265SDimitry Andric BR->markInteresting(ErrnoLoc->getAsRegion()); 156*81ad6265SDimitry Andric C.emitReport(std::move(BR)); 157*81ad6265SDimitry Andric } 158*81ad6265SDimitry Andric } 159*81ad6265SDimitry Andric break; 160*81ad6265SDimitry Andric case MustBeChecked: 161*81ad6265SDimitry Andric // 'errno' has to be checked. A load is required for this, with no more 162*81ad6265SDimitry Andric // information we can assume that it is checked somehow. 163*81ad6265SDimitry Andric // After this place 'errno' is allowed to be read and written. 164*81ad6265SDimitry Andric State = setErrnoStateIrrelevant(State); 165*81ad6265SDimitry Andric C.addTransition(State); 166*81ad6265SDimitry Andric break; 167*81ad6265SDimitry Andric default: 168*81ad6265SDimitry Andric break; 169*81ad6265SDimitry Andric } 170*81ad6265SDimitry Andric } else { 171*81ad6265SDimitry Andric switch (EState) { 172*81ad6265SDimitry Andric case MustBeChecked: 173*81ad6265SDimitry Andric // 'errno' is overwritten without a read before but it should have been 174*81ad6265SDimitry Andric // checked. 175*81ad6265SDimitry Andric generateErrnoNotCheckedBug(C, setErrnoStateIrrelevant(State), 176*81ad6265SDimitry Andric ErrnoLoc->getAsRegion(), nullptr); 177*81ad6265SDimitry Andric break; 178*81ad6265SDimitry Andric case MustNotBeChecked: 179*81ad6265SDimitry Andric // Write to 'errno' when it is not allowed to be read. 180*81ad6265SDimitry Andric // After this place 'errno' is allowed to be read and written. 181*81ad6265SDimitry Andric State = setErrnoStateIrrelevant(State); 182*81ad6265SDimitry Andric C.addTransition(State); 183*81ad6265SDimitry Andric break; 184*81ad6265SDimitry Andric default: 185*81ad6265SDimitry Andric break; 186*81ad6265SDimitry Andric } 187*81ad6265SDimitry Andric } 188*81ad6265SDimitry Andric } 189*81ad6265SDimitry Andric 190*81ad6265SDimitry Andric void ErrnoChecker::checkPreCall(const CallEvent &Call, 191*81ad6265SDimitry Andric CheckerContext &C) const { 192*81ad6265SDimitry Andric const auto *CallF = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 193*81ad6265SDimitry Andric if (!CallF) 194*81ad6265SDimitry Andric return; 195*81ad6265SDimitry Andric 196*81ad6265SDimitry Andric CallF = CallF->getCanonicalDecl(); 197*81ad6265SDimitry Andric // If 'errno' must be checked, it should be done as soon as possible, and 198*81ad6265SDimitry Andric // before any other call to a system function (something in a system header). 199*81ad6265SDimitry Andric // To avoid use of a long list of functions that may change 'errno' 200*81ad6265SDimitry Andric // (which may be different with standard library versions) assume that any 201*81ad6265SDimitry Andric // function can change it. 202*81ad6265SDimitry Andric // A list of special functions can be used that are allowed here without 203*81ad6265SDimitry Andric // generation of diagnostic. For now the only such case is 'errno' itself. 204*81ad6265SDimitry Andric // Probably 'strerror'? 205*81ad6265SDimitry Andric if (CallF->isExternC() && CallF->isGlobal() && 206*81ad6265SDimitry Andric C.getSourceManager().isInSystemHeader(CallF->getLocation()) && 207*81ad6265SDimitry Andric !isErrno(CallF)) { 208*81ad6265SDimitry Andric if (getErrnoState(C.getState()) == MustBeChecked) { 209*81ad6265SDimitry Andric Optional<ento::Loc> ErrnoLoc = getErrnoLoc(C.getState()); 210*81ad6265SDimitry Andric assert(ErrnoLoc && "ErrnoLoc should exist if an errno state is set."); 211*81ad6265SDimitry Andric generateErrnoNotCheckedBug(C, setErrnoStateIrrelevant(C.getState()), 212*81ad6265SDimitry Andric ErrnoLoc->getAsRegion(), &Call); 213*81ad6265SDimitry Andric } 214*81ad6265SDimitry Andric } 215*81ad6265SDimitry Andric } 216*81ad6265SDimitry Andric 217*81ad6265SDimitry Andric ProgramStateRef ErrnoChecker::checkRegionChanges( 218*81ad6265SDimitry Andric ProgramStateRef State, const InvalidatedSymbols *Invalidated, 219*81ad6265SDimitry Andric ArrayRef<const MemRegion *> ExplicitRegions, 220*81ad6265SDimitry Andric ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx, 221*81ad6265SDimitry Andric const CallEvent *Call) const { 222*81ad6265SDimitry Andric Optional<ento::Loc> ErrnoLoc = getErrnoLoc(State); 223*81ad6265SDimitry Andric if (!ErrnoLoc) 224*81ad6265SDimitry Andric return State; 225*81ad6265SDimitry Andric const MemRegion *ErrnoRegion = ErrnoLoc->getAsRegion(); 226*81ad6265SDimitry Andric 227*81ad6265SDimitry Andric // If 'errno' is invalidated we can not know if it is checked or written into, 228*81ad6265SDimitry Andric // allow read and write without bug reports. 229*81ad6265SDimitry Andric if (llvm::is_contained(Regions, ErrnoRegion)) 230*81ad6265SDimitry Andric return setErrnoStateIrrelevant(State); 231*81ad6265SDimitry Andric 232*81ad6265SDimitry Andric // Always reset errno state when the system memory space is invalidated. 233*81ad6265SDimitry Andric // The ErrnoRegion is not always found in the list in this case. 234*81ad6265SDimitry Andric if (llvm::is_contained(Regions, ErrnoRegion->getMemorySpace())) 235*81ad6265SDimitry Andric return setErrnoStateIrrelevant(State); 236*81ad6265SDimitry Andric 237*81ad6265SDimitry Andric return State; 238*81ad6265SDimitry Andric } 239*81ad6265SDimitry Andric 240*81ad6265SDimitry Andric void ento::registerErrnoChecker(CheckerManager &mgr) { 241*81ad6265SDimitry Andric const AnalyzerOptions &Opts = mgr.getAnalyzerOptions(); 242*81ad6265SDimitry Andric auto *Checker = mgr.registerChecker<ErrnoChecker>(); 243*81ad6265SDimitry Andric Checker->AllowErrnoReadOutsideConditions = Opts.getCheckerBooleanOption( 244*81ad6265SDimitry Andric Checker, "AllowErrnoReadOutsideConditionExpressions"); 245*81ad6265SDimitry Andric } 246*81ad6265SDimitry Andric 247*81ad6265SDimitry Andric bool ento::shouldRegisterErrnoChecker(const CheckerManager &mgr) { 248*81ad6265SDimitry Andric return true; 249*81ad6265SDimitry Andric } 250