xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp (revision ca4a405232cf170f20a2f111bf72beab82095935)
1d8a2afb2SBalázs Kéri //=== ErrnoModeling.cpp -----------------------------------------*- C++ -*-===//
2d8a2afb2SBalázs Kéri //
3d8a2afb2SBalázs Kéri // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4d8a2afb2SBalázs Kéri // See https://llvm.org/LICENSE.txt for license information.
5d8a2afb2SBalázs Kéri // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d8a2afb2SBalázs Kéri //
7d8a2afb2SBalázs Kéri //===----------------------------------------------------------------------===//
8d8a2afb2SBalázs Kéri //
9d8a2afb2SBalázs Kéri // This defines a checker `ErrnoModeling`, which is used to make the system
10d8a2afb2SBalázs Kéri // value 'errno' available to other checkers.
11d8a2afb2SBalázs Kéri // The 'errno' value is stored at a special memory region that is accessible
12d8a2afb2SBalázs Kéri // through the `errno_modeling` namespace. The memory region is either the
13d8a2afb2SBalázs Kéri // region of `errno` itself if it is a variable, otherwise an artifically
14d8a2afb2SBalázs Kéri // created region (in the system memory space). If `errno` is defined by using
15d8a2afb2SBalázs Kéri // a function which returns the address of it (this is always the case if it is
16d8a2afb2SBalázs Kéri // not a variable) this function is recognized and evaluated. In this way
17d8a2afb2SBalázs Kéri // `errno` becomes visible to the analysis and checkers can change its value.
18d8a2afb2SBalázs Kéri //
19d8a2afb2SBalázs Kéri //===----------------------------------------------------------------------===//
20d8a2afb2SBalázs Kéri 
21d8a2afb2SBalázs Kéri #include "ErrnoModeling.h"
22d8a2afb2SBalázs Kéri #include "clang/AST/ParentMapContext.h"
23d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
24d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Core/Checker.h"
25d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Core/CheckerManager.h"
26d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
27d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
28d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
29d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
30d8a2afb2SBalázs Kéri #include "llvm/ADT/STLExtras.h"
3139670ae3SBalázs Kéri #include "llvm/Support/FormatVariadic.h"
32a1580d7bSKazu Hirata #include <optional>
33d8a2afb2SBalázs Kéri 
34d8a2afb2SBalázs Kéri using namespace clang;
35d8a2afb2SBalázs Kéri using namespace ento;
36d8a2afb2SBalázs Kéri 
37d8a2afb2SBalázs Kéri namespace {
38d8a2afb2SBalázs Kéri 
39d8a2afb2SBalázs Kéri // Name of the "errno" variable.
40d8a2afb2SBalázs Kéri // FIXME: Is there a system where it is not called "errno" but is a variable?
41d8a2afb2SBalázs Kéri const char *ErrnoVarName = "errno";
42*ca4a4052SDonát Nagy 
43d8a2afb2SBalázs Kéri // Names of functions that return a location of the "errno" value.
44d8a2afb2SBalázs Kéri // FIXME: Are there other similar function names?
45*ca4a4052SDonát Nagy CallDescriptionSet ErrnoLocationCalls{
46*ca4a4052SDonát Nagy     {CDM::CLibrary, {"__errno_location"}, 0, 0},
47*ca4a4052SDonát Nagy     {CDM::CLibrary, {"___errno"}, 0, 0},
48*ca4a4052SDonát Nagy     {CDM::CLibrary, {"__errno"}, 0, 0},
49*ca4a4052SDonát Nagy     {CDM::CLibrary, {"_errno"}, 0, 0},
50*ca4a4052SDonát Nagy     {CDM::CLibrary, {"__error"}, 0, 0}};
51d8a2afb2SBalázs Kéri 
52d8a2afb2SBalázs Kéri class ErrnoModeling
53d8a2afb2SBalázs Kéri     : public Checker<check::ASTDecl<TranslationUnitDecl>, check::BeginFunction,
54d8a2afb2SBalázs Kéri                      check::LiveSymbols, eval::Call> {
55d8a2afb2SBalázs Kéri public:
56d8a2afb2SBalázs Kéri   void checkASTDecl(const TranslationUnitDecl *D, AnalysisManager &Mgr,
57d8a2afb2SBalázs Kéri                     BugReporter &BR) const;
58d8a2afb2SBalázs Kéri   void checkBeginFunction(CheckerContext &C) const;
59d8a2afb2SBalázs Kéri   void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
60d8a2afb2SBalázs Kéri   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
61d8a2afb2SBalázs Kéri 
62d8a2afb2SBalázs Kéri private:
63*ca4a4052SDonát Nagy   // The declaration of an "errno" variable on systems where errno is
64*ca4a4052SDonát Nagy   // represented by a variable (and not a function that queries its location).
65*ca4a4052SDonát Nagy   mutable const VarDecl *ErrnoDecl = nullptr;
66d8a2afb2SBalázs Kéri };
67d8a2afb2SBalázs Kéri 
68d8a2afb2SBalázs Kéri } // namespace
69d8a2afb2SBalázs Kéri 
70d8a2afb2SBalázs Kéri /// Store a MemRegion that contains the 'errno' integer value.
71d8a2afb2SBalázs Kéri /// The value is null if the 'errno' value was not recognized in the AST.
REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoRegion,const MemRegion *)72cf1f1b72SBalazs Benics REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoRegion, const MemRegion *)
73d8a2afb2SBalázs Kéri 
7460f3b071SBalázs Kéri REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoState, errno_modeling::ErrnoCheckState)
7560f3b071SBalázs Kéri 
76*ca4a4052SDonát Nagy void ErrnoModeling::checkASTDecl(const TranslationUnitDecl *D,
77*ca4a4052SDonát Nagy                                  AnalysisManager &Mgr, BugReporter &BR) const {
78*ca4a4052SDonát Nagy   // Try to find the declaration of the external variable `int errno;`.
79*ca4a4052SDonát Nagy   // There are also C library implementations, where the `errno` location is
80*ca4a4052SDonát Nagy   // accessed via a function that returns its address; in those environments
81*ca4a4052SDonát Nagy   // this callback has no effect.
82*ca4a4052SDonát Nagy   ASTContext &ACtx = Mgr.getASTContext();
83d8a2afb2SBalázs Kéri   IdentifierInfo &II = ACtx.Idents.get(ErrnoVarName);
84d8a2afb2SBalázs Kéri   auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
85d8a2afb2SBalázs Kéri   auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) {
86d8a2afb2SBalázs Kéri     if (auto *VD = dyn_cast<VarDecl>(D))
87d8a2afb2SBalázs Kéri       return ACtx.getSourceManager().isInSystemHeader(VD->getLocation()) &&
88d8a2afb2SBalázs Kéri              VD->hasExternalStorage() &&
89d8a2afb2SBalázs Kéri              VD->getType().getCanonicalType() == ACtx.IntTy;
90d8a2afb2SBalázs Kéri     return false;
91d8a2afb2SBalázs Kéri   });
92*ca4a4052SDonát Nagy   if (Found != LookupRes.end())
93*ca4a4052SDonát Nagy     ErrnoDecl = cast<VarDecl>(*Found);
94d8a2afb2SBalázs Kéri }
95d8a2afb2SBalázs Kéri 
checkBeginFunction(CheckerContext & C) const96d8a2afb2SBalázs Kéri void ErrnoModeling::checkBeginFunction(CheckerContext &C) const {
97d8a2afb2SBalázs Kéri   if (!C.inTopFrame())
98d8a2afb2SBalázs Kéri     return;
99d8a2afb2SBalázs Kéri 
100d8a2afb2SBalázs Kéri   ASTContext &ACtx = C.getASTContext();
101d8a2afb2SBalázs Kéri   ProgramStateRef State = C.getState();
102d8a2afb2SBalázs Kéri 
103*ca4a4052SDonát Nagy   const MemRegion *ErrnoR = nullptr;
104*ca4a4052SDonát Nagy 
105*ca4a4052SDonát Nagy   if (ErrnoDecl) {
106*ca4a4052SDonát Nagy     // There is an external 'errno' variable, so we can simply use the memory
107*ca4a4052SDonát Nagy     // region that's associated with it.
108*ca4a4052SDonát Nagy     ErrnoR = State->getRegion(ErrnoDecl, C.getLocationContext());
109d8a2afb2SBalázs Kéri     assert(ErrnoR && "Memory region should exist for the 'errno' variable.");
110*ca4a4052SDonát Nagy   } else {
111*ca4a4052SDonát Nagy     // There is no 'errno' variable, so create a new symbolic memory region
112*ca4a4052SDonát Nagy     // that can be used to model the return value of the "get the location of
113*ca4a4052SDonát Nagy     // errno" internal functions.
114*ca4a4052SDonát Nagy     // NOTE: this `SVal` is created even if errno is not defined or used.
115d8a2afb2SBalázs Kéri     SValBuilder &SVB = C.getSValBuilder();
116d8a2afb2SBalázs Kéri     MemRegionManager &RMgr = C.getStateManager().getRegionManager();
117d8a2afb2SBalázs Kéri 
118d8a2afb2SBalázs Kéri     const MemSpaceRegion *GlobalSystemSpace =
119d8a2afb2SBalázs Kéri         RMgr.getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind);
120d8a2afb2SBalázs Kéri 
121d8a2afb2SBalázs Kéri     // Create an artifical symbol for the region.
122*ca4a4052SDonát Nagy     // Note that it is not possible to associate a statement or expression in
123*ca4a4052SDonát Nagy     // this case and the `symbolTag` (opaque pointer tag) is just the address
124*ca4a4052SDonát Nagy     // of the data member `ErrnoDecl` of the singleton `ErrnoModeling` checker
125*ca4a4052SDonát Nagy     // object.
126d8a2afb2SBalázs Kéri     const SymbolConjured *Sym = SVB.conjureSymbol(
127d8a2afb2SBalázs Kéri         nullptr, C.getLocationContext(),
128d8a2afb2SBalázs Kéri         ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl);
129d8a2afb2SBalázs Kéri 
130d8a2afb2SBalázs Kéri     // The symbolic region is untyped, create a typed sub-region in it.
131d8a2afb2SBalázs Kéri     // The ElementRegion is used to make the errno region a typed region.
132*ca4a4052SDonát Nagy     ErrnoR = RMgr.getElementRegion(
133d8a2afb2SBalázs Kéri         ACtx.IntTy, SVB.makeZeroArrayIndex(),
134d8a2afb2SBalázs Kéri         RMgr.getSymbolicRegion(Sym, GlobalSystemSpace), C.getASTContext());
135*ca4a4052SDonát Nagy   }
136*ca4a4052SDonát Nagy   assert(ErrnoR);
137d8a2afb2SBalázs Kéri   State = State->set<ErrnoRegion>(ErrnoR);
13860f3b071SBalázs Kéri   State =
13960f3b071SBalázs Kéri       errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant);
140d8a2afb2SBalázs Kéri   C.addTransition(State);
141d8a2afb2SBalázs Kéri }
142d8a2afb2SBalázs Kéri 
evalCall(const CallEvent & Call,CheckerContext & C) const143d8a2afb2SBalázs Kéri bool ErrnoModeling::evalCall(const CallEvent &Call, CheckerContext &C) const {
144d8a2afb2SBalázs Kéri   // Return location of "errno" at a call to an "errno address returning"
145d8a2afb2SBalázs Kéri   // function.
146*ca4a4052SDonát Nagy   if (errno_modeling::isErrnoLocationCall(Call)) {
147d8a2afb2SBalázs Kéri     ProgramStateRef State = C.getState();
148d8a2afb2SBalázs Kéri 
149cf1f1b72SBalazs Benics     const MemRegion *ErrnoR = State->get<ErrnoRegion>();
150d8a2afb2SBalázs Kéri     if (!ErrnoR)
151d8a2afb2SBalázs Kéri       return false;
152d8a2afb2SBalázs Kéri 
153d8a2afb2SBalázs Kéri     State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
154d8a2afb2SBalázs Kéri                             loc::MemRegionVal{ErrnoR});
155d8a2afb2SBalázs Kéri     C.addTransition(State);
156d8a2afb2SBalázs Kéri     return true;
157d8a2afb2SBalázs Kéri   }
158d8a2afb2SBalázs Kéri 
159d8a2afb2SBalázs Kéri   return false;
160d8a2afb2SBalázs Kéri }
161d8a2afb2SBalázs Kéri 
checkLiveSymbols(ProgramStateRef State,SymbolReaper & SR) const162d8a2afb2SBalázs Kéri void ErrnoModeling::checkLiveSymbols(ProgramStateRef State,
163d8a2afb2SBalázs Kéri                                      SymbolReaper &SR) const {
164d8a2afb2SBalázs Kéri   // The special errno region should never garbage collected.
16560f3b071SBalázs Kéri   if (const auto *ErrnoR = State->get<ErrnoRegion>())
166d8a2afb2SBalázs Kéri     SR.markLive(ErrnoR);
167d8a2afb2SBalázs Kéri }
168d8a2afb2SBalázs Kéri 
169d8a2afb2SBalázs Kéri namespace clang {
170d8a2afb2SBalázs Kéri namespace ento {
171d8a2afb2SBalázs Kéri namespace errno_modeling {
172d8a2afb2SBalázs Kéri 
getErrnoValue(ProgramStateRef State)1736ad0788cSKazu Hirata std::optional<SVal> getErrnoValue(ProgramStateRef State) {
174cf1f1b72SBalazs Benics   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
175d8a2afb2SBalázs Kéri   if (!ErrnoR)
176d8a2afb2SBalázs Kéri     return {};
177d8a2afb2SBalázs Kéri   QualType IntTy = State->getAnalysisManager().getASTContext().IntTy;
178d8a2afb2SBalázs Kéri   return State->getSVal(ErrnoR, IntTy);
179d8a2afb2SBalázs Kéri }
180d8a2afb2SBalázs Kéri 
setErrnoValue(ProgramStateRef State,const LocationContext * LCtx,SVal Value,ErrnoCheckState EState)181d8a2afb2SBalázs Kéri ProgramStateRef setErrnoValue(ProgramStateRef State,
18260f3b071SBalázs Kéri                               const LocationContext *LCtx, SVal Value,
18360f3b071SBalázs Kéri                               ErrnoCheckState EState) {
184cf1f1b72SBalazs Benics   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
185d8a2afb2SBalázs Kéri   if (!ErrnoR)
186d8a2afb2SBalázs Kéri     return State;
18760f3b071SBalázs Kéri   // First set the errno value, the old state is still available at 'checkBind'
18860f3b071SBalázs Kéri   // or 'checkLocation' for errno value.
18960f3b071SBalázs Kéri   State = State->bindLoc(loc::MemRegionVal{ErrnoR}, Value, LCtx);
19060f3b071SBalázs Kéri   return State->set<ErrnoState>(EState);
191d8a2afb2SBalázs Kéri }
192d8a2afb2SBalázs Kéri 
setErrnoValue(ProgramStateRef State,CheckerContext & C,uint64_t Value,ErrnoCheckState EState)193d8a2afb2SBalázs Kéri ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C,
19460f3b071SBalázs Kéri                               uint64_t Value, ErrnoCheckState EState) {
195cf1f1b72SBalazs Benics   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
196d8a2afb2SBalázs Kéri   if (!ErrnoR)
197d8a2afb2SBalázs Kéri     return State;
19860f3b071SBalázs Kéri   State = State->bindLoc(
199d8a2afb2SBalázs Kéri       loc::MemRegionVal{ErrnoR},
200d8a2afb2SBalázs Kéri       C.getSValBuilder().makeIntVal(Value, C.getASTContext().IntTy),
201d8a2afb2SBalázs Kéri       C.getLocationContext());
20260f3b071SBalázs Kéri   return State->set<ErrnoState>(EState);
20360f3b071SBalázs Kéri }
20460f3b071SBalázs Kéri 
getErrnoLoc(ProgramStateRef State)2056ad0788cSKazu Hirata std::optional<Loc> getErrnoLoc(ProgramStateRef State) {
20660f3b071SBalázs Kéri   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
20760f3b071SBalázs Kéri   if (!ErrnoR)
20860f3b071SBalázs Kéri     return {};
20960f3b071SBalázs Kéri   return loc::MemRegionVal{ErrnoR};
21060f3b071SBalázs Kéri }
21160f3b071SBalázs Kéri 
getErrnoState(ProgramStateRef State)2123c7fe7d0SBalázs Kéri ErrnoCheckState getErrnoState(ProgramStateRef State) {
2133c7fe7d0SBalázs Kéri   return State->get<ErrnoState>();
2143c7fe7d0SBalázs Kéri }
2153c7fe7d0SBalázs Kéri 
setErrnoState(ProgramStateRef State,ErrnoCheckState EState)21660f3b071SBalázs Kéri ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState) {
21760f3b071SBalázs Kéri   return State->set<ErrnoState>(EState);
21860f3b071SBalázs Kéri }
21960f3b071SBalázs Kéri 
clearErrnoState(ProgramStateRef State)2203c7fe7d0SBalázs Kéri ProgramStateRef clearErrnoState(ProgramStateRef State) {
2213c7fe7d0SBalázs Kéri   return setErrnoState(State, Irrelevant);
22260f3b071SBalázs Kéri }
22360f3b071SBalázs Kéri 
isErrnoLocationCall(const CallEvent & CE)224*ca4a4052SDonát Nagy bool isErrnoLocationCall(const CallEvent &CE) {
225*ca4a4052SDonát Nagy   return ErrnoLocationCalls.contains(CE);
22660f3b071SBalázs Kéri }
22760f3b071SBalázs Kéri 
getErrnoNoteTag(CheckerContext & C,const std::string & Message)22860f3b071SBalázs Kéri const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message) {
22960f3b071SBalázs Kéri   return C.getNoteTag([Message](PathSensitiveBugReport &BR) -> std::string {
23060f3b071SBalázs Kéri     const MemRegion *ErrnoR = BR.getErrorNode()->getState()->get<ErrnoRegion>();
23160f3b071SBalázs Kéri     if (ErrnoR && BR.isInteresting(ErrnoR)) {
23260f3b071SBalázs Kéri       BR.markNotInteresting(ErrnoR);
23360f3b071SBalázs Kéri       return Message;
23460f3b071SBalázs Kéri     }
23560f3b071SBalázs Kéri     return "";
23660f3b071SBalázs Kéri   });
237d8a2afb2SBalázs Kéri }
238d8a2afb2SBalázs Kéri 
setErrnoForStdSuccess(ProgramStateRef State,CheckerContext & C)239d56a1c68SBalázs Kéri ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State,
240d56a1c68SBalázs Kéri                                       CheckerContext &C) {
241d56a1c68SBalázs Kéri   return setErrnoState(State, MustNotBeChecked);
242d56a1c68SBalázs Kéri }
243d56a1c68SBalázs Kéri 
setErrnoForStdFailure(ProgramStateRef State,CheckerContext & C,NonLoc ErrnoSym)244d56a1c68SBalázs Kéri ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C,
245d56a1c68SBalázs Kéri                                       NonLoc ErrnoSym) {
246d56a1c68SBalázs Kéri   SValBuilder &SVB = C.getSValBuilder();
247d56a1c68SBalázs Kéri   NonLoc ZeroVal = SVB.makeZeroVal(C.getASTContext().IntTy).castAs<NonLoc>();
248d56a1c68SBalázs Kéri   DefinedOrUnknownSVal Cond =
249d56a1c68SBalázs Kéri       SVB.evalBinOp(State, BO_NE, ErrnoSym, ZeroVal, SVB.getConditionType())
250d56a1c68SBalázs Kéri           .castAs<DefinedOrUnknownSVal>();
251d56a1c68SBalázs Kéri   State = State->assume(Cond, true);
252d56a1c68SBalázs Kéri   if (!State)
253d56a1c68SBalázs Kéri     return nullptr;
254d56a1c68SBalázs Kéri   return setErrnoValue(State, C.getLocationContext(), ErrnoSym, Irrelevant);
255d56a1c68SBalázs Kéri }
256d56a1c68SBalázs Kéri 
setErrnoStdMustBeChecked(ProgramStateRef State,CheckerContext & C,const Expr * InvalE)2573c7fe7d0SBalázs Kéri ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State,
2583c7fe7d0SBalázs Kéri                                          CheckerContext &C,
2593c7fe7d0SBalázs Kéri                                          const Expr *InvalE) {
2603c7fe7d0SBalázs Kéri   const MemRegion *ErrnoR = State->get<ErrnoRegion>();
2613c7fe7d0SBalázs Kéri   if (!ErrnoR)
2623c7fe7d0SBalázs Kéri     return State;
2633c7fe7d0SBalázs Kéri   State = State->invalidateRegions(ErrnoR, InvalE, C.blockCount(),
2643c7fe7d0SBalázs Kéri                                    C.getLocationContext(), false);
2653c7fe7d0SBalázs Kéri   if (!State)
2663c7fe7d0SBalázs Kéri     return nullptr;
2673c7fe7d0SBalázs Kéri   return setErrnoState(State, MustBeChecked);
2683c7fe7d0SBalázs Kéri }
2693c7fe7d0SBalázs Kéri 
270d8a2afb2SBalázs Kéri } // namespace errno_modeling
271d8a2afb2SBalázs Kéri } // namespace ento
272d8a2afb2SBalázs Kéri } // namespace clang
273d8a2afb2SBalázs Kéri 
registerErrnoModeling(CheckerManager & mgr)274d8a2afb2SBalázs Kéri void ento::registerErrnoModeling(CheckerManager &mgr) {
275d8a2afb2SBalázs Kéri   mgr.registerChecker<ErrnoModeling>();
276d8a2afb2SBalázs Kéri }
277d8a2afb2SBalázs Kéri 
shouldRegisterErrnoModeling(const CheckerManager & mgr)278d8a2afb2SBalázs Kéri bool ento::shouldRegisterErrnoModeling(const CheckerManager &mgr) {
279d8a2afb2SBalázs Kéri   return true;
280d8a2afb2SBalázs Kéri }
281