10b57cec5SDimitry Andric //===- Environment.cpp - Map from Stmt* to Locations/Values ---------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defined the Environment and EnvironmentManager classes.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h"
140b57cec5SDimitry Andric #include "clang/AST/Expr.h"
150b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h"
160b57cec5SDimitry Andric #include "clang/AST/PrettyPrinter.h"
170b57cec5SDimitry Andric #include "clang/AST/Stmt.h"
18e8d8bef9SDimitry Andric #include "clang/AST/StmtObjC.h"
190b57cec5SDimitry Andric #include "clang/Analysis/AnalysisDeclContext.h"
2006c3fb27SDimitry Andric #include "clang/Basic/JsonSupport.h"
210b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
220b57cec5SDimitry Andric #include "clang/Basic/LangOptions.h"
230b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
240b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
250b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
260b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
270b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
280b57cec5SDimitry Andric #include "llvm/ADT/ImmutableMap.h"
290b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
300b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
310b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
320b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
330b57cec5SDimitry Andric #include <cassert>
340b57cec5SDimitry Andric
350b57cec5SDimitry Andric using namespace clang;
360b57cec5SDimitry Andric using namespace ento;
370b57cec5SDimitry Andric
ignoreTransparentExprs(const Expr * E)380b57cec5SDimitry Andric static const Expr *ignoreTransparentExprs(const Expr *E) {
390b57cec5SDimitry Andric E = E->IgnoreParens();
400b57cec5SDimitry Andric
410b57cec5SDimitry Andric switch (E->getStmtClass()) {
420b57cec5SDimitry Andric case Stmt::OpaqueValueExprClass:
43*b3edf446SDimitry Andric if (const Expr *SE = cast<OpaqueValueExpr>(E)->getSourceExpr()) {
44*b3edf446SDimitry Andric E = SE;
450b57cec5SDimitry Andric break;
46*b3edf446SDimitry Andric }
47*b3edf446SDimitry Andric return E;
480b57cec5SDimitry Andric case Stmt::ExprWithCleanupsClass:
490b57cec5SDimitry Andric E = cast<ExprWithCleanups>(E)->getSubExpr();
500b57cec5SDimitry Andric break;
510b57cec5SDimitry Andric case Stmt::ConstantExprClass:
520b57cec5SDimitry Andric E = cast<ConstantExpr>(E)->getSubExpr();
530b57cec5SDimitry Andric break;
540b57cec5SDimitry Andric case Stmt::CXXBindTemporaryExprClass:
550b57cec5SDimitry Andric E = cast<CXXBindTemporaryExpr>(E)->getSubExpr();
560b57cec5SDimitry Andric break;
570b57cec5SDimitry Andric case Stmt::SubstNonTypeTemplateParmExprClass:
580b57cec5SDimitry Andric E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement();
590b57cec5SDimitry Andric break;
600b57cec5SDimitry Andric default:
610b57cec5SDimitry Andric // This is the base case: we can't look through more than we already have.
620b57cec5SDimitry Andric return E;
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric
650b57cec5SDimitry Andric return ignoreTransparentExprs(E);
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric
ignoreTransparentExprs(const Stmt * S)680b57cec5SDimitry Andric static const Stmt *ignoreTransparentExprs(const Stmt *S) {
690b57cec5SDimitry Andric if (const auto *E = dyn_cast<Expr>(S))
700b57cec5SDimitry Andric return ignoreTransparentExprs(E);
710b57cec5SDimitry Andric return S;
720b57cec5SDimitry Andric }
730b57cec5SDimitry Andric
EnvironmentEntry(const Stmt * S,const LocationContext * L)740b57cec5SDimitry Andric EnvironmentEntry::EnvironmentEntry(const Stmt *S, const LocationContext *L)
750b57cec5SDimitry Andric : std::pair<const Stmt *,
760b57cec5SDimitry Andric const StackFrameContext *>(ignoreTransparentExprs(S),
770b57cec5SDimitry Andric L ? L->getStackFrame()
780b57cec5SDimitry Andric : nullptr) {}
790b57cec5SDimitry Andric
lookupExpr(const EnvironmentEntry & E) const800b57cec5SDimitry Andric SVal Environment::lookupExpr(const EnvironmentEntry &E) const {
810b57cec5SDimitry Andric const SVal* X = ExprBindings.lookup(E);
820b57cec5SDimitry Andric if (X) {
830b57cec5SDimitry Andric SVal V = *X;
840b57cec5SDimitry Andric return V;
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric return UnknownVal();
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric
getSVal(const EnvironmentEntry & Entry,SValBuilder & svalBuilder) const890b57cec5SDimitry Andric SVal Environment::getSVal(const EnvironmentEntry &Entry,
900b57cec5SDimitry Andric SValBuilder& svalBuilder) const {
910b57cec5SDimitry Andric const Stmt *S = Entry.getStmt();
92e8d8bef9SDimitry Andric assert(!isa<ObjCForCollectionStmt>(S) &&
93e8d8bef9SDimitry Andric "Use ExprEngine::hasMoreIteration()!");
94349cc55cSDimitry Andric assert((isa<Expr, ReturnStmt>(S)) &&
95e8d8bef9SDimitry Andric "Environment can only argue about Exprs, since only they express "
96e8d8bef9SDimitry Andric "a value! Any non-expression statement stored in Environment is a "
97e8d8bef9SDimitry Andric "result of a hack!");
980b57cec5SDimitry Andric const LocationContext *LCtx = Entry.getLocationContext();
990b57cec5SDimitry Andric
1000b57cec5SDimitry Andric switch (S->getStmtClass()) {
1010b57cec5SDimitry Andric case Stmt::CXXBindTemporaryExprClass:
1020b57cec5SDimitry Andric case Stmt::ExprWithCleanupsClass:
1030b57cec5SDimitry Andric case Stmt::GenericSelectionExprClass:
1040b57cec5SDimitry Andric case Stmt::ConstantExprClass:
1050b57cec5SDimitry Andric case Stmt::ParenExprClass:
1060b57cec5SDimitry Andric case Stmt::SubstNonTypeTemplateParmExprClass:
1070b57cec5SDimitry Andric llvm_unreachable("Should have been handled by ignoreTransparentExprs");
1080b57cec5SDimitry Andric
1090b57cec5SDimitry Andric case Stmt::AddrLabelExprClass:
1100b57cec5SDimitry Andric case Stmt::CharacterLiteralClass:
1110b57cec5SDimitry Andric case Stmt::CXXBoolLiteralExprClass:
1120b57cec5SDimitry Andric case Stmt::CXXScalarValueInitExprClass:
1130b57cec5SDimitry Andric case Stmt::ImplicitValueInitExprClass:
1140b57cec5SDimitry Andric case Stmt::IntegerLiteralClass:
1150b57cec5SDimitry Andric case Stmt::ObjCBoolLiteralExprClass:
1160b57cec5SDimitry Andric case Stmt::CXXNullPtrLiteralExprClass:
1170b57cec5SDimitry Andric case Stmt::ObjCStringLiteralClass:
1180b57cec5SDimitry Andric case Stmt::StringLiteralClass:
1190b57cec5SDimitry Andric case Stmt::TypeTraitExprClass:
120a7dea167SDimitry Andric case Stmt::SizeOfPackExprClass:
121e8d8bef9SDimitry Andric case Stmt::PredefinedExprClass:
1220b57cec5SDimitry Andric // Known constants; defer to SValBuilder.
12381ad6265SDimitry Andric return *svalBuilder.getConstantVal(cast<Expr>(S));
1240b57cec5SDimitry Andric
1250b57cec5SDimitry Andric case Stmt::ReturnStmtClass: {
1260b57cec5SDimitry Andric const auto *RS = cast<ReturnStmt>(S);
1270b57cec5SDimitry Andric if (const Expr *RE = RS->getRetValue())
1280b57cec5SDimitry Andric return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder);
1290b57cec5SDimitry Andric return UndefinedVal();
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric
1320b57cec5SDimitry Andric // Handle all other Stmt* using a lookup.
1330b57cec5SDimitry Andric default:
1340b57cec5SDimitry Andric return lookupExpr(EnvironmentEntry(S, LCtx));
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric }
1370b57cec5SDimitry Andric
bindExpr(Environment Env,const EnvironmentEntry & E,SVal V,bool Invalidate)1380b57cec5SDimitry Andric Environment EnvironmentManager::bindExpr(Environment Env,
1390b57cec5SDimitry Andric const EnvironmentEntry &E,
1400b57cec5SDimitry Andric SVal V,
1410b57cec5SDimitry Andric bool Invalidate) {
1420b57cec5SDimitry Andric if (V.isUnknown()) {
1430b57cec5SDimitry Andric if (Invalidate)
1440b57cec5SDimitry Andric return Environment(F.remove(Env.ExprBindings, E));
1450b57cec5SDimitry Andric else
1460b57cec5SDimitry Andric return Env;
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric return Environment(F.add(Env.ExprBindings, E, V));
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric
1510b57cec5SDimitry Andric namespace {
1520b57cec5SDimitry Andric
1530b57cec5SDimitry Andric class MarkLiveCallback final : public SymbolVisitor {
1540b57cec5SDimitry Andric SymbolReaper &SymReaper;
1550b57cec5SDimitry Andric
1560b57cec5SDimitry Andric public:
MarkLiveCallback(SymbolReaper & symreaper)1570b57cec5SDimitry Andric MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {}
1580b57cec5SDimitry Andric
VisitSymbol(SymbolRef sym)1590b57cec5SDimitry Andric bool VisitSymbol(SymbolRef sym) override {
1600b57cec5SDimitry Andric SymReaper.markLive(sym);
1610b57cec5SDimitry Andric return true;
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric
VisitMemRegion(const MemRegion * R)1640b57cec5SDimitry Andric bool VisitMemRegion(const MemRegion *R) override {
1650b57cec5SDimitry Andric SymReaper.markLive(R);
1660b57cec5SDimitry Andric return true;
1670b57cec5SDimitry Andric }
1680b57cec5SDimitry Andric };
1690b57cec5SDimitry Andric
1700b57cec5SDimitry Andric } // namespace
1710b57cec5SDimitry Andric
1720b57cec5SDimitry Andric // removeDeadBindings:
1730b57cec5SDimitry Andric // - Remove subexpression bindings.
1740b57cec5SDimitry Andric // - Remove dead block expression bindings.
1750b57cec5SDimitry Andric // - Keep live block expression bindings:
1760b57cec5SDimitry Andric // - Mark their reachable symbols live in SymbolReaper,
1770b57cec5SDimitry Andric // see ScanReachableSymbols.
1780b57cec5SDimitry Andric // - Mark the region in DRoots if the binding is a loc::MemRegionVal.
1790b57cec5SDimitry Andric Environment
removeDeadBindings(Environment Env,SymbolReaper & SymReaper,ProgramStateRef ST)1800b57cec5SDimitry Andric EnvironmentManager::removeDeadBindings(Environment Env,
1810b57cec5SDimitry Andric SymbolReaper &SymReaper,
1820b57cec5SDimitry Andric ProgramStateRef ST) {
1830b57cec5SDimitry Andric // We construct a new Environment object entirely, as this is cheaper than
1840b57cec5SDimitry Andric // individually removing all the subexpression bindings (which will greatly
1850b57cec5SDimitry Andric // outnumber block-level expression bindings).
1860b57cec5SDimitry Andric Environment NewEnv = getInitialEnvironment();
1870b57cec5SDimitry Andric
1880b57cec5SDimitry Andric MarkLiveCallback CB(SymReaper);
1890b57cec5SDimitry Andric ScanReachableSymbols RSScaner(ST, CB);
1900b57cec5SDimitry Andric
1910b57cec5SDimitry Andric llvm::ImmutableMapRef<EnvironmentEntry, SVal>
1920b57cec5SDimitry Andric EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(),
1930b57cec5SDimitry Andric F.getTreeFactory());
1940b57cec5SDimitry Andric
1950b57cec5SDimitry Andric // Iterate over the block-expr bindings.
196e8d8bef9SDimitry Andric for (Environment::iterator I = Env.begin(), End = Env.end(); I != End; ++I) {
1970b57cec5SDimitry Andric const EnvironmentEntry &BlkExpr = I.getKey();
198647cbc5dSDimitry Andric SVal X = I.getData();
1990b57cec5SDimitry Andric
200e8d8bef9SDimitry Andric const Expr *E = dyn_cast<Expr>(BlkExpr.getStmt());
201e8d8bef9SDimitry Andric if (!E)
202e8d8bef9SDimitry Andric continue;
2035ffd83dbSDimitry Andric
204e8d8bef9SDimitry Andric if (SymReaper.isLive(E, BlkExpr.getLocationContext())) {
2050b57cec5SDimitry Andric // Copy the binding to the new map.
2060b57cec5SDimitry Andric EBMapRef = EBMapRef.add(BlkExpr, X);
2070b57cec5SDimitry Andric
2080b57cec5SDimitry Andric // Mark all symbols in the block expr's value live.
2090b57cec5SDimitry Andric RSScaner.scan(X);
2100b57cec5SDimitry Andric }
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric
2130b57cec5SDimitry Andric NewEnv.ExprBindings = EBMapRef.asImmutableMap();
2140b57cec5SDimitry Andric return NewEnv;
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric
printJson(raw_ostream & Out,const ASTContext & Ctx,const LocationContext * LCtx,const char * NL,unsigned int Space,bool IsDot) const2170b57cec5SDimitry Andric void Environment::printJson(raw_ostream &Out, const ASTContext &Ctx,
2180b57cec5SDimitry Andric const LocationContext *LCtx, const char *NL,
2190b57cec5SDimitry Andric unsigned int Space, bool IsDot) const {
2200b57cec5SDimitry Andric Indent(Out, Space, IsDot) << "\"environment\": ";
2210b57cec5SDimitry Andric
2220b57cec5SDimitry Andric if (ExprBindings.isEmpty()) {
2230b57cec5SDimitry Andric Out << "null," << NL;
2240b57cec5SDimitry Andric return;
2250b57cec5SDimitry Andric }
2260b57cec5SDimitry Andric
2270b57cec5SDimitry Andric ++Space;
2280b57cec5SDimitry Andric if (!LCtx) {
2290b57cec5SDimitry Andric // Find the freshest location context.
2300b57cec5SDimitry Andric llvm::SmallPtrSet<const LocationContext *, 16> FoundContexts;
2310b57cec5SDimitry Andric for (const auto &I : *this) {
2320b57cec5SDimitry Andric const LocationContext *LC = I.first.getLocationContext();
2330b57cec5SDimitry Andric if (FoundContexts.count(LC) == 0) {
2340b57cec5SDimitry Andric // This context is fresher than all other contexts so far.
2350b57cec5SDimitry Andric LCtx = LC;
2360b57cec5SDimitry Andric for (const LocationContext *LCI = LC; LCI; LCI = LCI->getParent())
2370b57cec5SDimitry Andric FoundContexts.insert(LCI);
2380b57cec5SDimitry Andric }
2390b57cec5SDimitry Andric }
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric
2420b57cec5SDimitry Andric assert(LCtx);
2430b57cec5SDimitry Andric
2440b57cec5SDimitry Andric Out << "{ \"pointer\": \"" << (const void *)LCtx->getStackFrame()
2450b57cec5SDimitry Andric << "\", \"items\": [" << NL;
2460b57cec5SDimitry Andric PrintingPolicy PP = Ctx.getPrintingPolicy();
2470b57cec5SDimitry Andric
2480b57cec5SDimitry Andric LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) {
2490b57cec5SDimitry Andric // LCtx items begin
2500b57cec5SDimitry Andric bool HasItem = false;
2510b57cec5SDimitry Andric unsigned int InnerSpace = Space + 1;
2520b57cec5SDimitry Andric
2530b57cec5SDimitry Andric // Store the last ExprBinding which we will print.
2540b57cec5SDimitry Andric BindingsTy::iterator LastI = ExprBindings.end();
2550b57cec5SDimitry Andric for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
2560b57cec5SDimitry Andric ++I) {
2570b57cec5SDimitry Andric if (I->first.getLocationContext() != LC)
2580b57cec5SDimitry Andric continue;
2590b57cec5SDimitry Andric
2600b57cec5SDimitry Andric if (!HasItem) {
2610b57cec5SDimitry Andric HasItem = true;
2620b57cec5SDimitry Andric Out << '[' << NL;
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric
2650b57cec5SDimitry Andric const Stmt *S = I->first.getStmt();
2660b57cec5SDimitry Andric (void)S;
2670b57cec5SDimitry Andric assert(S != nullptr && "Expected non-null Stmt");
2680b57cec5SDimitry Andric
2690b57cec5SDimitry Andric LastI = I;
2700b57cec5SDimitry Andric }
2710b57cec5SDimitry Andric
2720b57cec5SDimitry Andric for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
2730b57cec5SDimitry Andric ++I) {
2740b57cec5SDimitry Andric if (I->first.getLocationContext() != LC)
2750b57cec5SDimitry Andric continue;
2760b57cec5SDimitry Andric
2770b57cec5SDimitry Andric const Stmt *S = I->first.getStmt();
2780b57cec5SDimitry Andric Indent(Out, InnerSpace, IsDot)
279bdd1243dSDimitry Andric << "{ \"stmt_id\": " << S->getID(Ctx) << ", \"kind\": \""
280bdd1243dSDimitry Andric << S->getStmtClassName() << "\", \"pretty\": ";
2810b57cec5SDimitry Andric S->printJson(Out, nullptr, PP, /*AddQuotes=*/true);
2820b57cec5SDimitry Andric
2830b57cec5SDimitry Andric Out << ", \"value\": ";
2840b57cec5SDimitry Andric I->second.printJson(Out, /*AddQuotes=*/true);
2850b57cec5SDimitry Andric
2860b57cec5SDimitry Andric Out << " }";
2870b57cec5SDimitry Andric
2880b57cec5SDimitry Andric if (I != LastI)
2890b57cec5SDimitry Andric Out << ',';
2900b57cec5SDimitry Andric Out << NL;
2910b57cec5SDimitry Andric }
2920b57cec5SDimitry Andric
2930b57cec5SDimitry Andric if (HasItem)
2940b57cec5SDimitry Andric Indent(Out, --InnerSpace, IsDot) << ']';
2950b57cec5SDimitry Andric else
2960b57cec5SDimitry Andric Out << "null ";
2970b57cec5SDimitry Andric });
2980b57cec5SDimitry Andric
2990b57cec5SDimitry Andric Indent(Out, --Space, IsDot) << "]}," << NL;
3000b57cec5SDimitry Andric }
301