xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //=== ErrnoModeling.cpp -----------------------------------------*- C++ -*-===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This defines a checker `ErrnoModeling`, which is used to make the system
1081ad6265SDimitry Andric // value 'errno' available to other checkers.
1181ad6265SDimitry Andric // The 'errno' value is stored at a special memory region that is accessible
1281ad6265SDimitry Andric // through the `errno_modeling` namespace. The memory region is either the
1381ad6265SDimitry Andric // region of `errno` itself if it is a variable, otherwise an artifically
1481ad6265SDimitry Andric // created region (in the system memory space). If `errno` is defined by using
1581ad6265SDimitry Andric // a function which returns the address of it (this is always the case if it is
1681ad6265SDimitry Andric // not a variable) this function is recognized and evaluated. In this way
1781ad6265SDimitry Andric // `errno` becomes visible to the analysis and checkers can change its value.
1881ad6265SDimitry Andric //
1981ad6265SDimitry Andric //===----------------------------------------------------------------------===//
2081ad6265SDimitry Andric 
2181ad6265SDimitry Andric #include "ErrnoModeling.h"
2281ad6265SDimitry Andric #include "clang/AST/ParentMapContext.h"
2381ad6265SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
2481ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
2581ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
2681ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
2781ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
2881ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
2981ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
3081ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h"
3106c3fb27SDimitry Andric #include "llvm/Support/FormatVariadic.h"
32bdd1243dSDimitry Andric #include <optional>
3381ad6265SDimitry Andric 
3481ad6265SDimitry Andric using namespace clang;
3581ad6265SDimitry Andric using namespace ento;
3681ad6265SDimitry Andric 
3781ad6265SDimitry Andric namespace {
3881ad6265SDimitry Andric 
3981ad6265SDimitry Andric // Name of the "errno" variable.
4081ad6265SDimitry Andric // FIXME: Is there a system where it is not called "errno" but is a variable?
4181ad6265SDimitry Andric const char *ErrnoVarName = "errno";
42*0fca6ea1SDimitry Andric 
4381ad6265SDimitry Andric // Names of functions that return a location of the "errno" value.
4481ad6265SDimitry Andric // FIXME: Are there other similar function names?
45*0fca6ea1SDimitry Andric CallDescriptionSet ErrnoLocationCalls{
46*0fca6ea1SDimitry Andric     {CDM::CLibrary, {"__errno_location"}, 0, 0},
47*0fca6ea1SDimitry Andric     {CDM::CLibrary, {"___errno"}, 0, 0},
48*0fca6ea1SDimitry Andric     {CDM::CLibrary, {"__errno"}, 0, 0},
49*0fca6ea1SDimitry Andric     {CDM::CLibrary, {"_errno"}, 0, 0},
50*0fca6ea1SDimitry Andric     {CDM::CLibrary, {"__error"}, 0, 0}};
5181ad6265SDimitry Andric 
5281ad6265SDimitry Andric class ErrnoModeling
5381ad6265SDimitry Andric     : public Checker<check::ASTDecl<TranslationUnitDecl>, check::BeginFunction,
5481ad6265SDimitry Andric                      check::LiveSymbols, eval::Call> {
5581ad6265SDimitry Andric public:
5681ad6265SDimitry Andric   void checkASTDecl(const TranslationUnitDecl *D, AnalysisManager &Mgr,
5781ad6265SDimitry Andric                     BugReporter &BR) const;
5881ad6265SDimitry Andric   void checkBeginFunction(CheckerContext &C) const;
5981ad6265SDimitry Andric   void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
6081ad6265SDimitry Andric   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
6181ad6265SDimitry Andric 
6281ad6265SDimitry Andric private:
63*0fca6ea1SDimitry Andric   // The declaration of an "errno" variable on systems where errno is
64*0fca6ea1SDimitry Andric   // represented by a variable (and not a function that queries its location).
65*0fca6ea1SDimitry Andric   mutable const VarDecl *ErrnoDecl = nullptr;
6681ad6265SDimitry Andric };
6781ad6265SDimitry Andric 
6881ad6265SDimitry Andric } // namespace
6981ad6265SDimitry Andric 
7081ad6265SDimitry Andric /// Store a MemRegion that contains the 'errno' integer value.
7181ad6265SDimitry Andric /// The value is null if the 'errno' value was not recognized in the AST.
7281ad6265SDimitry Andric REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoRegion, const MemRegion *)
7381ad6265SDimitry Andric 
7481ad6265SDimitry Andric REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoState, errno_modeling::ErrnoCheckState)
7581ad6265SDimitry Andric 
76*0fca6ea1SDimitry Andric void ErrnoModeling::checkASTDecl(const TranslationUnitDecl *D,
77*0fca6ea1SDimitry Andric                                  AnalysisManager &Mgr, BugReporter &BR) const {
78*0fca6ea1SDimitry Andric   // Try to find the declaration of the external variable `int errno;`.
79*0fca6ea1SDimitry Andric   // There are also C library implementations, where the `errno` location is
80*0fca6ea1SDimitry Andric   // accessed via a function that returns its address; in those environments
81*0fca6ea1SDimitry Andric   // this callback has no effect.
82*0fca6ea1SDimitry Andric   ASTContext &ACtx = Mgr.getASTContext();
8381ad6265SDimitry Andric   IdentifierInfo &II = ACtx.Idents.get(ErrnoVarName);
8481ad6265SDimitry Andric   auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
8581ad6265SDimitry Andric   auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) {
8681ad6265SDimitry Andric     if (auto *VD = dyn_cast<VarDecl>(D))
8781ad6265SDimitry Andric       return ACtx.getSourceManager().isInSystemHeader(VD->getLocation()) &&
8881ad6265SDimitry Andric              VD->hasExternalStorage() &&
8981ad6265SDimitry Andric              VD->getType().getCanonicalType() == ACtx.IntTy;
9081ad6265SDimitry Andric     return false;
9181ad6265SDimitry Andric   });
92*0fca6ea1SDimitry Andric   if (Found != LookupRes.end())
93*0fca6ea1SDimitry Andric     ErrnoDecl = cast<VarDecl>(*Found);
9481ad6265SDimitry Andric }
9581ad6265SDimitry Andric 
9681ad6265SDimitry Andric void ErrnoModeling::checkBeginFunction(CheckerContext &C) const {
9781ad6265SDimitry Andric   if (!C.inTopFrame())
9881ad6265SDimitry Andric     return;
9981ad6265SDimitry Andric 
10081ad6265SDimitry Andric   ASTContext &ACtx = C.getASTContext();
10181ad6265SDimitry Andric   ProgramStateRef State = C.getState();
10281ad6265SDimitry Andric 
103*0fca6ea1SDimitry Andric   const MemRegion *ErrnoR = nullptr;
104*0fca6ea1SDimitry Andric 
105*0fca6ea1SDimitry Andric   if (ErrnoDecl) {
106*0fca6ea1SDimitry Andric     // There is an external 'errno' variable, so we can simply use the memory
107*0fca6ea1SDimitry Andric     // region that's associated with it.
108*0fca6ea1SDimitry Andric     ErrnoR = State->getRegion(ErrnoDecl, C.getLocationContext());
10981ad6265SDimitry Andric     assert(ErrnoR && "Memory region should exist for the 'errno' variable.");
110*0fca6ea1SDimitry Andric   } else {
111*0fca6ea1SDimitry Andric     // There is no 'errno' variable, so create a new symbolic memory region
112*0fca6ea1SDimitry Andric     // that can be used to model the return value of the "get the location of
113*0fca6ea1SDimitry Andric     // errno" internal functions.
114*0fca6ea1SDimitry Andric     // NOTE: this `SVal` is created even if errno is not defined or used.
11581ad6265SDimitry Andric     SValBuilder &SVB = C.getSValBuilder();
11681ad6265SDimitry Andric     MemRegionManager &RMgr = C.getStateManager().getRegionManager();
11781ad6265SDimitry Andric 
11881ad6265SDimitry Andric     const MemSpaceRegion *GlobalSystemSpace =
11981ad6265SDimitry Andric         RMgr.getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind);
12081ad6265SDimitry Andric 
12181ad6265SDimitry Andric     // Create an artifical symbol for the region.
122*0fca6ea1SDimitry Andric     // Note that it is not possible to associate a statement or expression in
123*0fca6ea1SDimitry Andric     // this case and the `symbolTag` (opaque pointer tag) is just the address
124*0fca6ea1SDimitry Andric     // of the data member `ErrnoDecl` of the singleton `ErrnoModeling` checker
125*0fca6ea1SDimitry Andric     // object.
12681ad6265SDimitry Andric     const SymbolConjured *Sym = SVB.conjureSymbol(
12781ad6265SDimitry Andric         nullptr, C.getLocationContext(),
12881ad6265SDimitry Andric         ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl);
12981ad6265SDimitry Andric 
13081ad6265SDimitry Andric     // The symbolic region is untyped, create a typed sub-region in it.
13181ad6265SDimitry Andric     // The ElementRegion is used to make the errno region a typed region.
132*0fca6ea1SDimitry Andric     ErrnoR = RMgr.getElementRegion(
13381ad6265SDimitry Andric         ACtx.IntTy, SVB.makeZeroArrayIndex(),
13481ad6265SDimitry Andric         RMgr.getSymbolicRegion(Sym, GlobalSystemSpace), C.getASTContext());
135*0fca6ea1SDimitry Andric   }
136*0fca6ea1SDimitry Andric   assert(ErrnoR);
13781ad6265SDimitry Andric   State = State->set<ErrnoRegion>(ErrnoR);
13881ad6265SDimitry Andric   State =
13981ad6265SDimitry Andric       errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant);
14081ad6265SDimitry Andric   C.addTransition(State);
14181ad6265SDimitry Andric }
14281ad6265SDimitry Andric 
14381ad6265SDimitry Andric bool ErrnoModeling::evalCall(const CallEvent &Call, CheckerContext &C) const {
14481ad6265SDimitry Andric   // Return location of "errno" at a call to an "errno address returning"
14581ad6265SDimitry Andric   // function.
146*0fca6ea1SDimitry Andric   if (errno_modeling::isErrnoLocationCall(Call)) {
14781ad6265SDimitry Andric     ProgramStateRef State = C.getState();
14881ad6265SDimitry Andric 
14981ad6265SDimitry Andric     const MemRegion *ErrnoR = State->get<ErrnoRegion>();
15081ad6265SDimitry Andric     if (!ErrnoR)
15181ad6265SDimitry Andric       return false;
15281ad6265SDimitry Andric 
15381ad6265SDimitry Andric     State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
15481ad6265SDimitry Andric                             loc::MemRegionVal{ErrnoR});
15581ad6265SDimitry Andric     C.addTransition(State);
15681ad6265SDimitry Andric     return true;
15781ad6265SDimitry Andric   }
15881ad6265SDimitry Andric 
15981ad6265SDimitry Andric   return false;
16081ad6265SDimitry Andric }
16181ad6265SDimitry Andric 
16281ad6265SDimitry Andric void ErrnoModeling::checkLiveSymbols(ProgramStateRef State,
16381ad6265SDimitry Andric                                      SymbolReaper &SR) const {
16481ad6265SDimitry Andric   // The special errno region should never garbage collected.
16581ad6265SDimitry Andric   if (const auto *ErrnoR = State->get<ErrnoRegion>())
16681ad6265SDimitry Andric     SR.markLive(ErrnoR);
16781ad6265SDimitry Andric }
16881ad6265SDimitry Andric 
16981ad6265SDimitry Andric namespace clang {
17081ad6265SDimitry Andric namespace ento {
17181ad6265SDimitry Andric namespace errno_modeling {
17281ad6265SDimitry Andric 
173bdd1243dSDimitry Andric std::optional<SVal> getErrnoValue(ProgramStateRef State) {
17481ad6265SDimitry Andric   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
17581ad6265SDimitry Andric   if (!ErrnoR)
17681ad6265SDimitry Andric     return {};
17781ad6265SDimitry Andric   QualType IntTy = State->getAnalysisManager().getASTContext().IntTy;
17881ad6265SDimitry Andric   return State->getSVal(ErrnoR, IntTy);
17981ad6265SDimitry Andric }
18081ad6265SDimitry Andric 
18181ad6265SDimitry Andric ProgramStateRef setErrnoValue(ProgramStateRef State,
18281ad6265SDimitry Andric                               const LocationContext *LCtx, SVal Value,
18381ad6265SDimitry Andric                               ErrnoCheckState EState) {
18481ad6265SDimitry Andric   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
18581ad6265SDimitry Andric   if (!ErrnoR)
18681ad6265SDimitry Andric     return State;
18781ad6265SDimitry Andric   // First set the errno value, the old state is still available at 'checkBind'
18881ad6265SDimitry Andric   // or 'checkLocation' for errno value.
18981ad6265SDimitry Andric   State = State->bindLoc(loc::MemRegionVal{ErrnoR}, Value, LCtx);
19081ad6265SDimitry Andric   return State->set<ErrnoState>(EState);
19181ad6265SDimitry Andric }
19281ad6265SDimitry Andric 
19381ad6265SDimitry Andric ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C,
19481ad6265SDimitry Andric                               uint64_t Value, ErrnoCheckState EState) {
19581ad6265SDimitry Andric   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
19681ad6265SDimitry Andric   if (!ErrnoR)
19781ad6265SDimitry Andric     return State;
19881ad6265SDimitry Andric   State = State->bindLoc(
19981ad6265SDimitry Andric       loc::MemRegionVal{ErrnoR},
20081ad6265SDimitry Andric       C.getSValBuilder().makeIntVal(Value, C.getASTContext().IntTy),
20181ad6265SDimitry Andric       C.getLocationContext());
20281ad6265SDimitry Andric   return State->set<ErrnoState>(EState);
20381ad6265SDimitry Andric }
20481ad6265SDimitry Andric 
205bdd1243dSDimitry Andric std::optional<Loc> getErrnoLoc(ProgramStateRef State) {
20681ad6265SDimitry Andric   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
20781ad6265SDimitry Andric   if (!ErrnoR)
20881ad6265SDimitry Andric     return {};
20981ad6265SDimitry Andric   return loc::MemRegionVal{ErrnoR};
21081ad6265SDimitry Andric }
21181ad6265SDimitry Andric 
212bdd1243dSDimitry Andric ErrnoCheckState getErrnoState(ProgramStateRef State) {
213bdd1243dSDimitry Andric   return State->get<ErrnoState>();
214bdd1243dSDimitry Andric }
215bdd1243dSDimitry Andric 
21681ad6265SDimitry Andric ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState) {
21781ad6265SDimitry Andric   return State->set<ErrnoState>(EState);
21881ad6265SDimitry Andric }
21981ad6265SDimitry Andric 
220bdd1243dSDimitry Andric ProgramStateRef clearErrnoState(ProgramStateRef State) {
221bdd1243dSDimitry Andric   return setErrnoState(State, Irrelevant);
22281ad6265SDimitry Andric }
22381ad6265SDimitry Andric 
224*0fca6ea1SDimitry Andric bool isErrnoLocationCall(const CallEvent &CE) {
225*0fca6ea1SDimitry Andric   return ErrnoLocationCalls.contains(CE);
22681ad6265SDimitry Andric }
22781ad6265SDimitry Andric 
22881ad6265SDimitry Andric const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message) {
22981ad6265SDimitry Andric   return C.getNoteTag([Message](PathSensitiveBugReport &BR) -> std::string {
23081ad6265SDimitry Andric     const MemRegion *ErrnoR = BR.getErrorNode()->getState()->get<ErrnoRegion>();
23181ad6265SDimitry Andric     if (ErrnoR && BR.isInteresting(ErrnoR)) {
23281ad6265SDimitry Andric       BR.markNotInteresting(ErrnoR);
23381ad6265SDimitry Andric       return Message;
23481ad6265SDimitry Andric     }
23581ad6265SDimitry Andric     return "";
23681ad6265SDimitry Andric   });
23781ad6265SDimitry Andric }
23881ad6265SDimitry Andric 
239bdd1243dSDimitry Andric ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State,
240bdd1243dSDimitry Andric                                       CheckerContext &C) {
241bdd1243dSDimitry Andric   return setErrnoState(State, MustNotBeChecked);
242bdd1243dSDimitry Andric }
243bdd1243dSDimitry Andric 
244bdd1243dSDimitry Andric ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C,
245bdd1243dSDimitry Andric                                       NonLoc ErrnoSym) {
246bdd1243dSDimitry Andric   SValBuilder &SVB = C.getSValBuilder();
247bdd1243dSDimitry Andric   NonLoc ZeroVal = SVB.makeZeroVal(C.getASTContext().IntTy).castAs<NonLoc>();
248bdd1243dSDimitry Andric   DefinedOrUnknownSVal Cond =
249bdd1243dSDimitry Andric       SVB.evalBinOp(State, BO_NE, ErrnoSym, ZeroVal, SVB.getConditionType())
250bdd1243dSDimitry Andric           .castAs<DefinedOrUnknownSVal>();
251bdd1243dSDimitry Andric   State = State->assume(Cond, true);
252bdd1243dSDimitry Andric   if (!State)
253bdd1243dSDimitry Andric     return nullptr;
254bdd1243dSDimitry Andric   return setErrnoValue(State, C.getLocationContext(), ErrnoSym, Irrelevant);
255bdd1243dSDimitry Andric }
256bdd1243dSDimitry Andric 
257bdd1243dSDimitry Andric ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State,
258bdd1243dSDimitry Andric                                          CheckerContext &C,
259bdd1243dSDimitry Andric                                          const Expr *InvalE) {
260bdd1243dSDimitry Andric   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
261bdd1243dSDimitry Andric   if (!ErrnoR)
262bdd1243dSDimitry Andric     return State;
263bdd1243dSDimitry Andric   State = State->invalidateRegions(ErrnoR, InvalE, C.blockCount(),
264bdd1243dSDimitry Andric                                    C.getLocationContext(), false);
265bdd1243dSDimitry Andric   if (!State)
266bdd1243dSDimitry Andric     return nullptr;
267bdd1243dSDimitry Andric   return setErrnoState(State, MustBeChecked);
268bdd1243dSDimitry Andric }
269bdd1243dSDimitry Andric 
27081ad6265SDimitry Andric } // namespace errno_modeling
27181ad6265SDimitry Andric } // namespace ento
27281ad6265SDimitry Andric } // namespace clang
27381ad6265SDimitry Andric 
27481ad6265SDimitry Andric void ento::registerErrnoModeling(CheckerManager &mgr) {
27581ad6265SDimitry Andric   mgr.registerChecker<ErrnoModeling>();
27681ad6265SDimitry Andric }
27781ad6265SDimitry Andric 
27881ad6265SDimitry Andric bool ento::shouldRegisterErrnoModeling(const CheckerManager &mgr) {
27981ad6265SDimitry Andric   return true;
28081ad6265SDimitry Andric }
281