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