clang 20.0.0git
ExprEngineC.cpp
Go to the documentation of this file.
1//=-- ExprEngineC.cpp - ExprEngine support for C expressions ----*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines ExprEngine's support for C expressions.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/AST/DeclCXX.h"
14#include "clang/AST/ExprCXX.h"
17#include <optional>
18
19using namespace clang;
20using namespace ento;
21using llvm::APSInt;
22
23/// Optionally conjure and return a symbol for offset when processing
24/// an expression \p Expression.
25/// If \p Other is a location, conjure a symbol for \p Symbol
26/// (offset) if it is unknown so that memory arithmetic always
27/// results in an ElementRegion.
28/// \p Count The number of times the current basic block was visited.
30 SVal Symbol, SVal Other, Expr* Expression, SValBuilder &svalBuilder,
31 unsigned Count, const LocationContext *LCtx) {
32 QualType Ty = Expression->getType();
33 if (isa<Loc>(Other) && Ty->isIntegralOrEnumerationType() &&
34 Symbol.isUnknown()) {
35 return svalBuilder.conjureSymbolVal(Expression, LCtx, Ty, Count);
36 }
37 return Symbol;
38}
39
41 ExplodedNode *Pred,
42 ExplodedNodeSet &Dst) {
43
44 Expr *LHS = B->getLHS()->IgnoreParens();
45 Expr *RHS = B->getRHS()->IgnoreParens();
46
47 // FIXME: Prechecks eventually go in ::Visit().
48 ExplodedNodeSet CheckedSet;
49 ExplodedNodeSet Tmp2;
50 getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, B, *this);
51
52 // With both the LHS and RHS evaluated, process the operation itself.
53 for (ExplodedNodeSet::iterator it=CheckedSet.begin(), ei=CheckedSet.end();
54 it != ei; ++it) {
55
56 ProgramStateRef state = (*it)->getState();
57 const LocationContext *LCtx = (*it)->getLocationContext();
58 SVal LeftV = state->getSVal(LHS, LCtx);
59 SVal RightV = state->getSVal(RHS, LCtx);
60
62
63 if (Op == BO_Assign) {
64 // EXPERIMENTAL: "Conjured" symbols.
65 // FIXME: Handle structs.
66 if (RightV.isUnknown()) {
67 unsigned Count = currBldrCtx->blockCount();
68 RightV = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx,
69 Count);
70 }
71 // Simulate the effects of a "store": bind the value of the RHS
72 // to the L-Value represented by the LHS.
73 SVal ExprVal = B->isGLValue() ? LeftV : RightV;
74 evalStore(Tmp2, B, LHS, *it, state->BindExpr(B, LCtx, ExprVal),
75 LeftV, RightV);
76 continue;
77 }
78
79 if (!B->isAssignmentOp()) {
80 StmtNodeBuilder Bldr(*it, Tmp2, *currBldrCtx);
81
82 if (B->isAdditiveOp()) {
83 // TODO: This can be removed after we enable history tracking with
84 // SymSymExpr.
85 unsigned Count = currBldrCtx->blockCount();
87 RightV, LeftV, RHS, svalBuilder, Count, LCtx);
89 LeftV, RightV, LHS, svalBuilder, Count, LCtx);
90 }
91
92 // Although we don't yet model pointers-to-members, we do need to make
93 // sure that the members of temporaries have a valid 'this' pointer for
94 // other checks.
95 if (B->getOpcode() == BO_PtrMemD)
96 state = createTemporaryRegionIfNeeded(state, LCtx, LHS);
97
98 // Process non-assignments except commas or short-circuited
99 // logical expressions (LAnd and LOr).
100 SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType());
101 if (!Result.isUnknown()) {
102 state = state->BindExpr(B, LCtx, Result);
103 } else {
104 // If we cannot evaluate the operation escape the operands.
105 state = escapeValues(state, LeftV, PSK_EscapeOther);
106 state = escapeValues(state, RightV, PSK_EscapeOther);
107 }
108
109 Bldr.generateNode(B, *it, state);
110 continue;
111 }
112
113 assert (B->isCompoundAssignmentOp());
114
115 switch (Op) {
116 default:
117 llvm_unreachable("Invalid opcode for compound assignment.");
118 case BO_MulAssign: Op = BO_Mul; break;
119 case BO_DivAssign: Op = BO_Div; break;
120 case BO_RemAssign: Op = BO_Rem; break;
121 case BO_AddAssign: Op = BO_Add; break;
122 case BO_SubAssign: Op = BO_Sub; break;
123 case BO_ShlAssign: Op = BO_Shl; break;
124 case BO_ShrAssign: Op = BO_Shr; break;
125 case BO_AndAssign: Op = BO_And; break;
126 case BO_XorAssign: Op = BO_Xor; break;
127 case BO_OrAssign: Op = BO_Or; break;
128 }
129
130 // Perform a load (the LHS). This performs the checks for
131 // null dereferences, and so on.
132 ExplodedNodeSet Tmp;
133 SVal location = LeftV;
134 evalLoad(Tmp, B, LHS, *it, state, location);
135
136 for (ExplodedNode *N : Tmp) {
137 state = N->getState();
138 const LocationContext *LCtx = N->getLocationContext();
139 SVal V = state->getSVal(LHS, LCtx);
140
141 // Get the computation type.
142 QualType CTy =
143 cast<CompoundAssignOperator>(B)->getComputationResultType();
144 CTy = getContext().getCanonicalType(CTy);
145
146 QualType CLHSTy =
147 cast<CompoundAssignOperator>(B)->getComputationLHSType();
148 CLHSTy = getContext().getCanonicalType(CLHSTy);
149
151
152 // Promote LHS.
153 V = svalBuilder.evalCast(V, CLHSTy, LTy);
154
155 // Compute the result of the operation.
156 SVal Result = svalBuilder.evalCast(evalBinOp(state, Op, V, RightV, CTy),
157 B->getType(), CTy);
158
159 // EXPERIMENTAL: "Conjured" symbols.
160 // FIXME: Handle structs.
161
162 SVal LHSVal;
163
164 if (Result.isUnknown()) {
165 // The symbolic value is actually for the type of the left-hand side
166 // expression, not the computation type, as this is the value the
167 // LValue on the LHS will bind to.
168 LHSVal = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx, LTy,
169 currBldrCtx->blockCount());
170 // However, we need to convert the symbol to the computation type.
171 Result = svalBuilder.evalCast(LHSVal, CTy, LTy);
172 } else {
173 // The left-hand side may bind to a different value then the
174 // computation type.
175 LHSVal = svalBuilder.evalCast(Result, LTy, CTy);
176 }
177
178 // In C++, assignment and compound assignment operators return an
179 // lvalue.
180 if (B->isGLValue())
181 state = state->BindExpr(B, LCtx, location);
182 else
183 state = state->BindExpr(B, LCtx, Result);
184
185 evalStore(Tmp2, B, LHS, N, state, location, LHSVal);
186 }
187 }
188
189 // FIXME: postvisits eventually go in ::Visit()
190 getCheckerManager().runCheckersForPostStmt(Dst, Tmp2, B, *this);
191}
192
194 ExplodedNodeSet &Dst) {
195
197
198 const BlockDecl *BD = BE->getBlockDecl();
199 // Get the value of the block itself.
200 SVal V = svalBuilder.getBlockPointer(BD, T,
201 Pred->getLocationContext(),
202 currBldrCtx->blockCount());
203
204 ProgramStateRef State = Pred->getState();
205
206 // If we created a new MemRegion for the block, we should explicitly bind
207 // the captured variables.
208 if (const BlockDataRegion *BDR =
209 dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) {
210
211 auto ReferencedVars = BDR->referenced_vars();
212 auto CI = BD->capture_begin();
213 auto CE = BD->capture_end();
214 for (auto Var : ReferencedVars) {
215 const VarRegion *capturedR = Var.getCapturedRegion();
216 const TypedValueRegion *originalR = Var.getOriginalRegion();
217
218 // If the capture had a copy expression, use the result of evaluating
219 // that expression, otherwise use the original value.
220 // We rely on the invariant that the block declaration's capture variables
221 // are a prefix of the BlockDataRegion's referenced vars (which may include
222 // referenced globals, etc.) to enable fast lookup of the capture for a
223 // given referenced var.
224 const Expr *copyExpr = nullptr;
225 if (CI != CE) {
226 assert(CI->getVariable() == capturedR->getDecl());
227 copyExpr = CI->getCopyExpr();
228 CI++;
229 }
230
231 if (capturedR != originalR) {
232 SVal originalV;
233 const LocationContext *LCtx = Pred->getLocationContext();
234 if (copyExpr) {
235 originalV = State->getSVal(copyExpr, LCtx);
236 } else {
237 originalV = State->getSVal(loc::MemRegionVal(originalR));
238 }
239 State = State->bindLoc(loc::MemRegionVal(capturedR), originalV, LCtx);
240 }
241 }
242 }
243
244 ExplodedNodeSet Tmp;
245 StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
246 Bldr.generateNode(BE, Pred,
247 State->BindExpr(BE, Pred->getLocationContext(), V),
249
250 // FIXME: Move all post/pre visits to ::Visit().
251 getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this);
252}
253
255 ProgramStateRef state, const Expr* Ex, const LocationContext* LCtx,
256 QualType T, QualType ExTy, const CastExpr* CastE, StmtNodeBuilder& Bldr,
257 ExplodedNode* Pred) {
258 if (T->isLValueReferenceType()) {
259 assert(!CastE->getType()->isLValueReferenceType());
260 ExTy = getContext().getLValueReferenceType(ExTy);
261 } else if (T->isRValueReferenceType()) {
262 assert(!CastE->getType()->isRValueReferenceType());
263 ExTy = getContext().getRValueReferenceType(ExTy);
264 }
265 // Delegate to SValBuilder to process.
266 SVal OrigV = state->getSVal(Ex, LCtx);
267 SVal SimplifiedOrigV = svalBuilder.simplifySVal(state, OrigV);
268 SVal V = svalBuilder.evalCast(SimplifiedOrigV, T, ExTy);
269 // Negate the result if we're treating the boolean as a signed i1
270 if (CastE->getCastKind() == CK_BooleanToSignedIntegral && V.isValid())
271 V = svalBuilder.evalMinus(V.castAs<NonLoc>());
272
273 state = state->BindExpr(CastE, LCtx, V);
274 if (V.isUnknown() && !OrigV.isUnknown()) {
275 state = escapeValues(state, OrigV, PSK_EscapeOther);
276 }
277 Bldr.generateNode(CastE, Pred, state);
278
279 return state;
280}
281
282void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
283 ExplodedNode *Pred, ExplodedNodeSet &Dst) {
284
285 ExplodedNodeSet dstPreStmt;
286 getCheckerManager().runCheckersForPreStmt(dstPreStmt, Pred, CastE, *this);
287
288 if (CastE->getCastKind() == CK_LValueToRValue ||
289 CastE->getCastKind() == CK_LValueToRValueBitCast) {
290 for (ExplodedNode *subExprNode : dstPreStmt) {
291 ProgramStateRef state = subExprNode->getState();
292 const LocationContext *LCtx = subExprNode->getLocationContext();
293 evalLoad(Dst, CastE, CastE, subExprNode, state, state->getSVal(Ex, LCtx));
294 }
295 return;
296 }
297
298 // All other casts.
299 QualType T = CastE->getType();
300 QualType ExTy = Ex->getType();
301
302 if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
303 T = ExCast->getTypeAsWritten();
304
305 StmtNodeBuilder Bldr(dstPreStmt, Dst, *currBldrCtx);
306 for (ExplodedNode *Pred : dstPreStmt) {
307 ProgramStateRef state = Pred->getState();
308 const