| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | #include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h" |
| 14 | #include "clang/AST/Expr.h" |
| 15 | #include "clang/AST/ExprCXX.h" |
| 16 | #include "clang/AST/PrettyPrinter.h" |
| 17 | #include "clang/AST/Stmt.h" |
| 18 | #include "clang/Analysis/AnalysisDeclContext.h" |
| 19 | #include "clang/Basic/LLVM.h" |
| 20 | #include "clang/Basic/LangOptions.h" |
| 21 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" |
| 22 | #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" |
| 23 | #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" |
| 24 | #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" |
| 25 | #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" |
| 26 | #include "llvm/ADT/ImmutableMap.h" |
| 27 | #include "llvm/ADT/SmallPtrSet.h" |
| 28 | #include "llvm/Support/Casting.h" |
| 29 | #include "llvm/Support/ErrorHandling.h" |
| 30 | #include "llvm/Support/raw_ostream.h" |
| 31 | #include <cassert> |
| 32 | |
| 33 | using namespace clang; |
| 34 | using namespace ento; |
| 35 | |
| 36 | static const Expr *ignoreTransparentExprs(const Expr *E) { |
| 37 | E = E->IgnoreParens(); |
| 38 | |
| 39 | switch (E->getStmtClass()) { |
| 40 | case Stmt::OpaqueValueExprClass: |
| 41 | E = cast<OpaqueValueExpr>(E)->getSourceExpr(); |
| 42 | break; |
| 43 | case Stmt::ExprWithCleanupsClass: |
| 44 | E = cast<ExprWithCleanups>(E)->getSubExpr(); |
| 45 | break; |
| 46 | case Stmt::ConstantExprClass: |
| 47 | E = cast<ConstantExpr>(E)->getSubExpr(); |
| 48 | break; |
| 49 | case Stmt::CXXBindTemporaryExprClass: |
| 50 | E = cast<CXXBindTemporaryExpr>(E)->getSubExpr(); |
| 51 | break; |
| 52 | case Stmt::SubstNonTypeTemplateParmExprClass: |
| 53 | E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(); |
| 54 | break; |
| 55 | default: |
| 56 | |
| 57 | return E; |
| 58 | } |
| 59 | |
| 60 | return ignoreTransparentExprs(E); |
| 61 | } |
| 62 | |
| 63 | static const Stmt *ignoreTransparentExprs(const Stmt *S) { |
| 64 | if (const auto *E = dyn_cast<Expr>(S)) |
| 65 | return ignoreTransparentExprs(E); |
| 66 | return S; |
| 67 | } |
| 68 | |
| 69 | EnvironmentEntry::EnvironmentEntry(const Stmt *S, const LocationContext *L) |
| 70 | : std::pair<const Stmt *, |
| 71 | const StackFrameContext *>(ignoreTransparentExprs(S), |
| 72 | L ? L->getStackFrame() |
| 73 | : nullptr) {} |
| 74 | |
| 75 | SVal Environment::lookupExpr(const EnvironmentEntry &E) const { |
| 76 | const SVal* X = ExprBindings.lookup(E); |
| 77 | if (X) { |
| 78 | SVal V = *X; |
| 79 | return V; |
| 80 | } |
| 81 | return UnknownVal(); |
| 82 | } |
| 83 | |
| 84 | SVal Environment::getSVal(const EnvironmentEntry &Entry, |
| 85 | SValBuilder& svalBuilder) const { |
| 86 | const Stmt *S = Entry.getStmt(); |
| 87 | const LocationContext *LCtx = Entry.getLocationContext(); |
| 88 | |
| 89 | switch (S->getStmtClass()) { |
| 90 | case Stmt::CXXBindTemporaryExprClass: |
| 91 | case Stmt::ExprWithCleanupsClass: |
| 92 | case Stmt::GenericSelectionExprClass: |
| 93 | case Stmt::OpaqueValueExprClass: |
| 94 | case Stmt::ConstantExprClass: |
| 95 | case Stmt::ParenExprClass: |
| 96 | case Stmt::SubstNonTypeTemplateParmExprClass: |
| 97 | llvm_unreachable("Should have been handled by ignoreTransparentExprs"); |
| 98 | |
| 99 | case Stmt::AddrLabelExprClass: |
| 100 | case Stmt::CharacterLiteralClass: |
| 101 | case Stmt::CXXBoolLiteralExprClass: |
| 102 | case Stmt::CXXScalarValueInitExprClass: |
| 103 | case Stmt::ImplicitValueInitExprClass: |
| 104 | case Stmt::IntegerLiteralClass: |
| 105 | case Stmt::ObjCBoolLiteralExprClass: |
| 106 | case Stmt::CXXNullPtrLiteralExprClass: |
| 107 | case Stmt::ObjCStringLiteralClass: |
| 108 | case Stmt::StringLiteralClass: |
| 109 | case Stmt::TypeTraitExprClass: |
| 110 | |
| 111 | return svalBuilder.getConstantVal(cast<Expr>(S)).getValue(); |
| 112 | |
| 113 | case Stmt::ReturnStmtClass: { |
| 114 | const auto *RS = cast<ReturnStmt>(S); |
| 115 | if (const Expr *RE = RS->getRetValue()) |
| 116 | return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder); |
| 117 | return UndefinedVal(); |
| 118 | } |
| 119 | |
| 120 | |
| 121 | default: |
| 122 | return lookupExpr(EnvironmentEntry(S, LCtx)); |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | Environment EnvironmentManager::bindExpr(Environment Env, |
| 127 | const EnvironmentEntry &E, |
| 128 | SVal V, |
| 129 | bool Invalidate) { |
| 130 | if (V.isUnknown()) { |
| 131 | if (Invalidate) |
| 132 | return Environment(F.remove(Env.ExprBindings, E)); |
| 133 | else |
| 134 | return Env; |
| 135 | } |
| 136 | return Environment(F.add(Env.ExprBindings, E, V)); |
| 137 | } |
| 138 | |
| 139 | namespace { |
| 140 | |
| 141 | class MarkLiveCallback final : public SymbolVisitor { |
| 142 | SymbolReaper &SymReaper; |
| 143 | |
| 144 | public: |
| 145 | MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {} |
| 146 | |
| 147 | bool VisitSymbol(SymbolRef sym) override { |
| 148 | SymReaper.markLive(sym); |
| 149 | return true; |
| 150 | } |
| 151 | |
| 152 | bool VisitMemRegion(const MemRegion *R) override { |
| 153 | SymReaper.markLive(R); |
| 154 | return true; |
| 155 | } |
| 156 | }; |
| 157 | |
| 158 | } |
| 159 | |
| 160 | |
| 161 | |
| 162 | |
| 163 | |
| 164 | |
| 165 | |
| 166 | |
| 167 | Environment |
| 168 | EnvironmentManager::removeDeadBindings(Environment Env, |
| 169 | SymbolReaper &SymReaper, |
| 170 | ProgramStateRef ST) { |
| 171 | |
| 172 | |
| 173 | |
| 174 | Environment NewEnv = getInitialEnvironment(); |
| 175 | |
| 176 | MarkLiveCallback CB(SymReaper); |
| 177 | ScanReachableSymbols (ST, CB); |
| 178 | |
| 179 | llvm::ImmutableMapRef<EnvironmentEntry, SVal> |
| 180 | EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(), |
| 181 | F.getTreeFactory()); |
| 182 | |
| 183 | |
| 184 | for (Environment::iterator I = Env.begin(), E = Env.end(); |
| 185 | I != E; ++I) { |
| 186 | const EnvironmentEntry &BlkExpr = I.getKey(); |
| 187 | const SVal &X = I.getData(); |
| 188 | |
| 189 | if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) { |
| 190 | |
| 191 | EBMapRef = EBMapRef.add(BlkExpr, X); |
| 192 | |
| 193 | |
| 194 | RSScaner.scan(X); |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | NewEnv.ExprBindings = EBMapRef.asImmutableMap(); |
| 199 | return NewEnv; |
| 200 | } |
| 201 | |
| 202 | void Environment::print(raw_ostream &Out, const char *NL, |
| 203 | const char *Sep, |
| 204 | const ASTContext &Context, |
| 205 | const LocationContext *WithLC) const { |
| 206 | if (ExprBindings.isEmpty()) |
| 207 | return; |
| 208 | |
| 209 | if (!WithLC) { |
| 210 | |
| 211 | llvm::SmallPtrSet<const LocationContext *, 16> FoundContexts; |
| 212 | for (auto I : *this) { |
| 213 | const LocationContext *LC = I.first.getLocationContext(); |
| 214 | if (FoundContexts.count(LC) == 0) { |
| 215 | |
| 216 | WithLC = LC; |
| 217 | for (const LocationContext *LCI = LC; LCI; LCI = LCI->getParent()) |
| 218 | FoundContexts.insert(LCI); |
| 219 | } |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | assert(WithLC); |
| 224 | |
| 225 | PrintingPolicy PP = Context.getPrintingPolicy(); |
| 226 | |
| 227 | Out << NL << "Expressions by stack frame:" << NL; |
| 228 | WithLC->dumpStack(Out, "", NL, Sep, [&](const LocationContext *LC) { |
| 229 | for (auto I : ExprBindings) { |
| 230 | if (I.first.getLocationContext() != LC) |
| 231 | continue; |
| 232 | |
| 233 | const Stmt *S = I.first.getStmt(); |
| 234 | (0) . __assert_fail ("S != nullptr && \"Expected non-null Stmt\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/Environment.cpp", 234, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(S != nullptr && "Expected non-null Stmt"); |
| 235 | |
| 236 | Out << "(LC" << LC->getID() << ", S" << S->getID(Context) << ") "; |
| 237 | S->printPretty(Out, , PP); |
| 238 | Out << " : " << I.second << NL; |
| 239 | } |
| 240 | }); |
| 241 | } |
| 242 | |