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"
15#include "clang/StaticAnalyzer/Core/CheckerManager.h"
16#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
17#include <optional>
18
19using namespace clang;
20using namespace ento;
21using llvm::APSInt;
22
23void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
24 ExplodedNode *Pred,
25 ExplodedNodeSet &Dst) {
26 const StackFrame *SF = Pred->getStackFrame();
27
28 Expr *LHS = B->getLHS()->IgnoreParens();
29 Expr *RHS = B->getRHS()->IgnoreParens();
30
31 // FIXME: Prechecks eventually go in ::Visit().
32 ExplodedNodeSet CheckedSet;
33 ExplodedNodeSet Tmp2;
34 getCheckerManager().runCheckersForPreStmt(Dst&: CheckedSet, Src: Pred, S: B, Eng&: *this);
35
36 // With both the LHS and RHS evaluated, process the operation itself.
37 for (ExplodedNode *N : CheckedSet) {
38 ProgramStateRef State = N->getState();
39 SVal LeftV = State->getSVal(E: LHS, SF);
40 SVal RightV = State->getSVal(E: RHS, SF);
41
42 BinaryOperator::Opcode Op = B->getOpcode();
43
44 if (Op == BO_Assign) {
45 if (RightV.isUnknown()) {
46 unsigned Count = getNumVisitedCurrent();
47 RightV = svalBuilder.conjureSymbolVal(symbolTag: nullptr, elem: getCFGElementRef(), SF,
48 count: Count);
49 }
50 // Simulate the effects of a "store": bind the value of the RHS
51 // to the L-Value represented by the LHS.
52 SVal ExprVal = B->isGLValue() ? LeftV : RightV;
53 evalStore(Dst&: Tmp2, AssignE: B, StoreE: LHS, Pred: N, St: State->BindExpr(E: B, SF, V: ExprVal), TargetLV: LeftV,
54 Val: RightV);
55 continue;
56 }
57
58 if (!B->isAssignmentOp()) {
59 if (B->isAdditiveOp()) {
60 // Ensure that if `p` is a pointer and `i` is an integer with Unknown
61 // value, then `p+i`, `i+p` and `p-i` are evaluated to element regions
62 // (with a symbolic offset) instead of Unknown.
63 auto ConjureIfNeeded = [this, SF](SVal &V, SVal Other, QualType VTy) {
64 if (isa<Loc>(Val: Other) && VTy->isIntegralOrEnumerationType() &&
65 V.isUnknown()) {
66 V = svalBuilder.conjureSymbolVal(elem: getCFGElementRef(), SF, type: VTy,
67 visitCount: getNumVisitedCurrent());
68 }
69 };
70 ConjureIfNeeded(RightV, LeftV, RHS->getType());
71 ConjureIfNeeded(LeftV, RightV, LHS->getType());
72 }
73
74 // Although we don't yet model pointers-to-members, we do need to make
75 // sure that the members of temporaries have a valid 'this' pointer for
76 // other checks.
77 if (B->getOpcode() == BO_PtrMemD)
78 State = createTemporaryRegionIfNeeded(State, SF, InitWithAdjustments: LHS);
79
80 // Process non-assignments except commas or short-circuited
81 // logical expressions (LAnd and LOr).
82 SVal Result = evalBinOp(ST: State, Op, LHS: LeftV, RHS: RightV, T: B->getType());
83 if (!Result.isUnknown()) {
84 State = State->BindExpr(E: B, SF, V: Result);
85 } else {
86 // If we cannot evaluate the operation escape the operands.
87 State = escapeValues(State, Vs: LeftV, K: PSK_EscapeOther);
88 State = escapeValues(State, Vs: RightV, K: PSK_EscapeOther);
89 }
90
91 Tmp2.insert(N: Engine.makePostStmtNode(S: B, State, Pred: N));
92 continue;
93 }
94
95 assert (B->isCompoundAssignmentOp());
96
97 switch (Op) {
98 default:
99 llvm_unreachable("Invalid opcode for compound assignment.");
100 case BO_MulAssign: Op = BO_Mul; break;
101 case BO_DivAssign: Op = BO_Div; break;
102 case BO_RemAssign: Op = BO_Rem; break;
103 case BO_AddAssign: Op = BO_Add; break;
104 case BO_SubAssign: Op = BO_Sub; break;
105 case BO_ShlAssign: Op = BO_Shl; break;
106 case BO_ShrAssign: Op = BO_Shr; break;
107 case BO_AndAssign: Op = BO_And; break;
108 case BO_XorAssign: Op = BO_Xor; break;
109 case BO_OrAssign: Op = BO_Or; break;
110 }
111
112 // Perform a load (the LHS). This performs the checks for
113 // null dereferences, and so on.
114 ExplodedNodeSet Tmp;
115 evalLoad(Dst&: Tmp, NodeEx: B, BoundExpr: LHS, Pred: N, St: State, location: LeftV);
116
117 for (ExplodedNode *N : Tmp) {
118 State = N->getState();
119 SVal V = State->getSVal(E: LHS, SF);
120
121 // Determine the relevant types.
122 const ASTContext &ACtx = getContext();
123 const auto *CAOpB = cast<CompoundAssignOperator>(Val: B);
124 QualType CTy = ACtx.getCanonicalType(T: CAOpB->getComputationResultType());
125 QualType CLHSTy = ACtx.getCanonicalType(T: CAOpB->getComputationLHSType());
126 QualType LTy = ACtx.getCanonicalType(T: LHS->getType());
127
128 // Promote LHS.
129 V = svalBuilder.evalCast(V, CastTy: CLHSTy, OriginalTy: LTy);
130
131 // Compute the result of the operation.
132 SVal Result = svalBuilder.evalCast(V: evalBinOp(ST: State, Op, LHS: V, RHS: RightV, T: CTy),
133 CastTy: B->getType(), OriginalTy: CTy);
134
135 SVal StoredInLeftV;
136
137 if (Result.isUnknown()) {
138 // The symbolic value is actually for the type of the left-hand side
139 // expression, not the computation type, as this is the value the
140 // LValue on the LHS will bind to.
141 StoredInLeftV = svalBuilder.conjureSymbolVal(
142 /*symbolTag=*/nullptr, elem: getCFGElementRef(), SF, type: LTy,
143 count: getNumVisitedCurrent());
144 // However, we need to convert the symbol to the computation type.
145 Result = svalBuilder.evalCast(V: StoredInLeftV, CastTy: CTy, OriginalTy: LTy);
146 } else {
147 // The left-hand side may bind to a different value then the
148 // computation type.
149 StoredInLeftV = svalBuilder.evalCast(V: Result, CastTy: LTy, OriginalTy: CTy);
150 }
151
152 // In C++, assignment and compound assignment operators return an
153 // lvalue.
154 if (B->isGLValue())
155 State = State->BindExpr(E: B, SF, V: LeftV);
156 else
157 State = State->BindExpr(E: B, SF, V: Result);
158
159 evalStore(Dst&: Tmp2, AssignE: B, StoreE: LHS, Pred: N, St: State, TargetLV: LeftV, Val: StoredInLeftV);
160 }
161 }
162
163 // FIXME: postvisits eventually go in ::Visit()
164 getCheckerManager().runCheckersForPostStmt(Dst, Src: Tmp2, S: B, Eng&: *this);
165}
166
167void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
168 ExplodedNodeSet &Dst) {
169
170 CanQualType T = getContext().getCanonicalType(T: BE->getType());
171
172 const BlockDecl *BD = BE->getBlockDecl();
173 // Get the value of the block itself.
174 SVal V = svalBuilder.getBlockPointer(block: BD, locTy: T, SF: Pred->getStackFrame(),
175 blockCount: getNumVisitedCurrent());
176
177 ProgramStateRef State = Pred->getState();
178
179 // If we created a new MemRegion for the block, we should explicitly bind
180 // the captured variables.
181 if (const BlockDataRegion *BDR =
182 dyn_cast_or_null<BlockDataRegion>(Val: V.getAsRegion())) {
183
184 auto ReferencedVars = BDR->referenced_vars();
185 auto CI = BD->capture_begin();
186 auto CE = BD->capture_end();
187 for (auto Var : ReferencedVars) {
188 const VarRegion *capturedR = Var.getCapturedRegion();
189 const TypedValueRegion *originalR = Var.getOriginalRegion();
190
191 // If the capture had a copy expression, use the result of evaluating
192 // that expression, otherwise use the original value.
193 // We rely on the invariant that the block declaration's capture variables
194 // are a prefix of the BlockDataRegion's referenced vars (which may include
195 // referenced globals, etc.) to enable fast lookup of the capture for a
196 // given referenced var.
197 const Expr *copyExpr = nullptr;
198 if (CI != CE) {
199 assert(CI->getVariable() == capturedR->getDecl());
200 copyExpr = CI->getCopyExpr();
201 CI++;
202 }
203
204 if (capturedR != originalR) {
205 SVal originalV;
206 const StackFrame *SF = Pred->getStackFrame();
207 if (copyExpr) {
208 originalV = State->getSVal(E: copyExpr, SF);
209 } else {
210 originalV = State->getSVal(LV: loc::MemRegionVal(originalR));
211 }
212 State = State->bindLoc(location: loc::MemRegionVal(capturedR), V: originalV, SF);
213 }
214 }
215 }
216
217 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: BE, V, State,
218 K: ProgramPoint::PostLValueKind));
219}
220
221void ExprEngine::handleLValueBitCast(ProgramStateRef state, const Expr *Ex,
222 const StackFrame *SF, QualType T,
223 QualType ExTy, const CastExpr *CastE,
224 ExplodedNodeSet &Dst, ExplodedNode *Pred) {
225 if (T->isLValueReferenceType()) {
226 assert(!CastE->getType()->isLValueReferenceType());
227 ExTy = getContext().getLValueReferenceType(T: ExTy);
228 } else if (T->isRValueReferenceType()) {
229 assert(!CastE->getType()->isRValueReferenceType());
230 ExTy = getContext().getRValueReferenceType(T: ExTy);
231 }
232 // Delegate to SValBuilder to process.
233 SVal OrigV = state->getSVal(E: Ex, SF);
234 SVal SimplifiedOrigV = svalBuilder.simplifySVal(State: state, Val: OrigV);
235 SVal V = svalBuilder.evalCast(V: SimplifiedOrigV, CastTy: T, OriginalTy: ExTy);
236 // Negate the result if we're treating the boolean as a signed i1
237 if (CastE->getCastKind() == CK_BooleanToSignedIntegral && V.isValid())
238 V = svalBuilder.evalMinus(val: V.castAs<NonLoc>());
239
240 state = state->BindExpr(E: CastE, SF, V);
241 if (V.isUnknown() && !OrigV.isUnknown()) {
242 state = escapeValues(State: state, Vs: OrigV, K: PSK_EscapeOther);
243 }
244 Dst.insert(N: Engine.makePostStmtNode(S: CastE, State: state, Pred));
245}
246
247void ExprEngine::VisitCastExpr(const CastExpr *CastE, ExplodedNode *Pred,
248 ExplodedNodeSet &Dst) {
249 const Expr *Ex = CastE->getSubExpr();
250 ProgramStateRef State = Pred->getState();
251 const StackFrame *SF = Pred->getStackFrame();
252
253 if (CastE->getCastKind() == CK_LValueToRValue) {
254 evalLoad(Dst, NodeEx: CastE, BoundExpr: CastE, Pred, St: State, location: State->getSVal(E: Ex, SF));
255 return;
256 }
257 if (CastE->getCastKind() == CK_LValueToRValueBitCast) {
258 // Handle `__builtin_bit_cast`:
259 ExplodedNodeSet DstEvalLoc;
260
261 // Simulate the lvalue-to-rvalue conversion on `Ex`:
262 evalLocation(Dst&: DstEvalLoc, NodeEx: CastE, BoundEx: Ex, Pred, St: State, location: State->getSVal(E: Ex, SF),
263 isLoad: true);
264 // Simulate the operation that actually casts the original value to a new
265 // value of the destination type :
266
267 for (ExplodedNode *Node : DstEvalLoc) {
268 ProgramStateRef State = Node->getState();
269 const StackFrame *SF = Node->getStackFrame();
270 // Although `Ex` is an lvalue, it could have `Loc::ConcreteInt` kind
271 // (e.g., `(int *)123456`). In such cases, there is no MemRegion
272 // available and we can't get the value to be casted.
273 SVal CastedV = UnknownVal();
274
275 if (const MemRegion *MR = State->getSVal(E: Ex, SF).getAsRegion()) {
276 SVal OrigV = State->getSVal(R: MR);
277 CastedV = svalBuilder.evalCast(V: svalBuilder.simplifySVal(State, Val: OrigV),
278 CastTy: CastE->getType(), OriginalTy: Ex->getType());
279 }
280 Dst.insert(N: Engine.makeNodeWithBinding(Pred: Node, E: CastE, V: CastedV));
281 }
282 return;
283 }
284
285 // All other casts.
286 QualType T = CastE->getType();
287 QualType ExTy = Ex->getType();
288
289 if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(Val: CastE))
290 T = ExCast->getTypeAsWritten();
291
292 switch (CastE->getCastKind()) {
293 case CK_LValueToRValue:
294 case CK_LValueToRValueBitCast:
295 llvm_unreachable("LValueToRValue casts handled earlier.");
296 case CK_ToVoid:
297 Dst.insert(N: Pred);
298 return;
299 // The analyzer doesn't do anything special with these casts,
300 // since it understands retain/release semantics already.
301 case CK_ARCProduceObject:
302 case CK_ARCConsumeObject:
303 case CK_ARCReclaimReturnedObject:
304 case CK_ARCExtendBlockObject: // Fall-through.
305 case CK_CopyAndAutoreleaseBlockObject:
306 // The analyser can ignore atomic casts for now, although some future
307 // checkers may want to make certain that you're not modifying the same
308 // value through atomic and nonatomic pointers.
309 case CK_AtomicToNonAtomic:
310 case CK_NonAtomicToAtomic:
311 // True no-ops.
312 case CK_NoOp:
313 case CK_ConstructorConversion:
314 case CK_UserDefinedConversion:
315 case CK_FunctionToPointerDecay:
316 case CK_BuiltinFnToFnPtr:
317 case CK_HLSLArrayRValue: {
318 // Copy the SVal of Ex to CastE.
319 SVal V = State->getSVal(E: Ex, SF);
320 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: CastE, V));
321 return;
322 }
323 case CK_MemberPointerToBoolean:
324 case CK_PointerToBoolean: {
325 SVal V = State->getSVal(E: Ex, SF);
326 auto PTMSV = V.getAs<nonloc::PointerToMember>();
327 if (PTMSV)
328 V = svalBuilder.makeTruthVal(b: !PTMSV->isNullMemberPointer(), type: ExTy);
329 if (V.isUndef() || PTMSV) {
330 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: CastE, V));
331 return;
332 }
333 handleLValueBitCast(state: State, Ex, SF, T, ExTy, CastE, Dst, Pred);
334 return;
335 }
336 case CK_Dependent:
337 case CK_ArrayToPointerDecay:
338 case CK_BitCast:
339 case CK_AddressSpaceConversion:
340 case CK_BooleanToSignedIntegral:
341 case CK_IntegralToPointer:
342 case CK_PointerToIntegral: {
343 SVal V = State->getSVal(E: Ex, SF);
344 if (isa<nonloc::PointerToMember>(Val: V)) {
345 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: CastE, V: UnknownVal()));
346 return;
347 }
348 handleLValueBitCast(state: State, Ex, SF, T, ExTy, CastE, Dst, Pred);
349 return;
350 }
351 case CK_IntegralToBoolean:
352 case CK_IntegralToFloating:
353 case CK_FloatingToIntegral:
354 case CK_FloatingToBoolean:
355 case CK_FloatingCast:
356 case CK_FloatingRealToComplex:
357 case CK_FloatingComplexToReal:
358 case CK_FloatingComplexToBoolean:
359 case CK_FloatingComplexCast:
360 case CK_FloatingComplexToIntegralComplex:
361 case CK_IntegralRealToComplex:
362 case CK_IntegralComplexToReal:
363 case CK_IntegralComplexToBoolean:
364 case CK_IntegralComplexCast:
365 case CK_IntegralComplexToFloatingComplex:
366 case CK_CPointerToObjCPointerCast:
367 case CK_BlockPointerToObjCPointerCast:
368 case CK_AnyPointerToBlockPointerCast:
369 case CK_ObjCObjectLValueCast:
370 case CK_ZeroToOCLOpaqueType:
371 case CK_IntToOCLSampler:
372 case CK_LValueBitCast:
373 case CK_FloatingToFixedPoint:
374 case CK_FixedPointToFloating:
375 case CK_FixedPointCast:
376 case CK_FixedPointToBoolean:
377 case CK_FixedPointToIntegral:
378 case CK_IntegralToFixedPoint: {
379 handleLValueBitCast(state: State, Ex, SF, T, ExTy, CastE, Dst, Pred);
380 return;
381 }
382 case CK_IntegralCast: {
383 // Delegate to SValBuilder to process.
384 SVal V = State->getSVal(E: Ex, SF);
385 if (AMgr.options.analyzerSymbolicIntegerCasts())
386 V = svalBuilder.evalCast(V, CastTy: T, OriginalTy: ExTy);
387 else
388 V = svalBuilder.evalIntegralCast(state: State, val: V, castTy: T, originalType: ExTy);
389 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: CastE, V));
390 return;
391 }
392 case CK_DerivedToBase:
393 case CK_UncheckedDerivedToBase: {
394 // For DerivedToBase cast, delegate to the store manager.
395 SVal val = State->getSVal(E: Ex, SF);
396 val = getStoreManager().evalDerivedToBase(Derived: val, Cast: CastE);
397 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: CastE, V: val));
398 return;
399 }
400 // Handle C++ dyn_cast.
401 case CK_Dynamic: {
402 SVal val = State->getSVal(E: Ex, SF);
403
404 // Compute the type of the result.
405 QualType resultType = CastE->getType();
406 if (CastE->isGLValue())
407 resultType = getContext().getPointerType(T: resultType);
408
409 bool Failed = true;
410
411 // Check if the value being cast does not evaluates to 0.
412 if (!val.isZeroConstant())
413 if (std::optional<SVal> V =
414 StateMgr.getStoreManager().evalBaseToDerived(Base: val, DerivedPtrType: T)) {
415 val = *V;
416 Failed = false;
417 }
418
419 if (Failed) {
420 if (T->isReferenceType()) {
421 // A bad_cast exception is thrown if input value is a reference.
422 // Currently, we model this, by generating a sink.
423 Engine.makePostStmtNode(S: CastE, State, Pred, /*MarkAsSink=*/true);
424 return;
425 } else {
426 // If the cast fails on a pointer, bind to 0.
427 State = State->BindExpr(E: CastE, SF,
428 V: svalBuilder.makeNullWithType(type: resultType));
429 }
430 } else {
431 // If we don't know if the cast succeeded, conjure a new symbol.
432 if (val.isUnknown()) {
433 DefinedOrUnknownSVal NewSym = svalBuilder.conjureSymbolVal(
434 /*symbolTag=*/nullptr, elem: getCFGElementRef(), SF, type: resultType,
435 count: getNumVisitedCurrent());
436 State = State->BindExpr(E: CastE, SF, V: NewSym);
437 } else
438 // Else, bind to the derived region value.
439 State = State->BindExpr(E: CastE, SF, V: val);
440 }
441 Dst.insert(N: Engine.makePostStmtNode(S: CastE, State, Pred));
442 return;
443 }
444 case CK_BaseToDerived: {
445 SVal val = State->getSVal(E: Ex, SF);
446 QualType resultType = CastE->getType();
447 if (CastE->isGLValue())
448 resultType = getContext().getPointerType(T: resultType);
449
450 if (!val.isConstant()) {
451 std::optional<SVal> V = getStoreManager().evalBaseToDerived(Base: val, DerivedPtrType: T);
452 val = V ? *V : UnknownVal();
453 }
454
455 // Failed to cast or the result is unknown, fall back to conservative.
456 if (val.isUnknown()) {
457 val = svalBuilder.conjureSymbolVal(
458 /*symbolTag=*/nullptr, elem: getCFGElementRef(), SF, type: resultType,
459 count: getNumVisitedCurrent());
460 }
461 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: CastE, V: val));
462 return;
463 }
464 case CK_NullToPointer: {
465 SVal V = svalBuilder.makeNullWithType(type: CastE->getType());
466 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: CastE, V));
467 return;
468 }
469 case CK_NullToMemberPointer: {
470 SVal V = svalBuilder.getMemberPointer(ND: nullptr);
471 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: CastE, V));
472 return;
473 }
474 case CK_DerivedToBaseMemberPointer:
475 case CK_BaseToDerivedMemberPointer:
476 case CK_ReinterpretMemberPointer: {
477 SVal V = State->getSVal(E: Ex, SF);
478 if (auto PTMSV = V.getAs<nonloc::PointerToMember>()) {
479 SVal CastedPTMSV =
480 svalBuilder.makePointerToMember(PTMD: getBasicVals().accumCXXBase(
481 PathRange: CastE->path(), PTM: *PTMSV, kind: CastE->getCastKind()));
482 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: CastE, V: CastedPTMSV));
483 return;
484 }
485 // Explicitly proceed with default handler for this case cascade.
486 }
487 [[fallthrough]];
488 // Various C++ casts that are not handled yet.
489 case CK_ToUnion:
490 case CK_MatrixCast:
491 case CK_VectorSplat:
492 case CK_HLSLElementwiseCast:
493 case CK_HLSLAggregateSplatCast:
494 case CK_HLSLMatrixTruncation:
495 case CK_HLSLVectorTruncation: {
496 QualType resultType = CastE->getType();
497 if (CastE->isGLValue())
498 resultType = getContext().getPointerType(T: resultType);
499 SVal result = svalBuilder.conjureSymbolVal(
500 /*symbolTag=*/nullptr, elem: getCFGElementRef(), SF, type: resultType,
501 count: getNumVisitedCurrent());
502 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: CastE, V: result));
503 return;
504 }
505 }
506}
507
508void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
509 ExplodedNode *Pred,
510 ExplodedNodeSet &Dst) {
511 ProgramStateRef State = Pred->getState();
512 const StackFrame *SF = Pred->getStackFrame();
513
514 const Expr *Init = CL->getInitializer();
515 SVal V = State->getSVal(E: CL->getInitializer(), SF);
516
517 if (isa<CXXConstructExpr, CXXStdInitializerListExpr>(Val: Init)) {
518 // No work needed. Just pass the value up to this expression.
519 } else {
520 assert(isa<InitListExpr>(Init));
521 Loc CLLoc = State->getLValue(literal: CL, SF);
522 State = State->bindLoc(location: CLLoc, V, SF);
523
524 if (CL->isGLValue())
525 V = CLLoc;
526 }
527
528 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: CL, V, State));
529}
530
531void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
532 ExplodedNodeSet &Dst) {
533 if (isa<TypedefNameDecl>(Val: *DS->decl_begin())) {
534 // C99 6.7.7 "Any array size expressions associated with variable length
535 // array declarators are evaluated each time the declaration of the typedef
536 // name is reached in the order of execution."
537 // The checkers should know about typedef to be able to handle VLA size
538 // expressions.
539 ExplodedNodeSet DstPre;
540 getCheckerManager().runCheckersForPreStmt(Dst&: DstPre, Src: Pred, S: DS, Eng&: *this);
541 getCheckerManager().runCheckersForPostStmt(Dst, Src: DstPre, S: DS, Eng&: *this);
542 return;
543 }
544
545 // Assumption: The CFG has one DeclStmt per Decl.
546 const VarDecl *VD = dyn_cast_or_null<VarDecl>(Val: *DS->decl_begin());
547
548 if (!VD) {
549 //TODO:AZ: remove explicit insertion after refactoring is done.
550 Dst.insert(N: Pred);
551 return;
552 }
553
554 // Self-assignment initialization in variable declaration,
555 // i.e., `int x = x;`,
556 // is a C idiom to suppress warnings of unused variables.
557 // This filter will not match variables of C++ record types, but will match
558 // C++ references. Allow references continuing here to make the undefined
559 // value checker report self-assignments of C++ references.
560 if (const Expr *EI = VD->getInit()) {
561 // Ignore InitListExpr if exists.
562 if (const auto *IL = dyn_cast<InitListExpr>(Val: EI);
563 IL && IL->getNumInits() == 1)
564 EI = IL->getInit(Init: 0);
565
566 // Ignore parentheses and implict casts.
567 if (const auto *DR = dyn_cast<DeclRefExpr>(Val: EI->IgnoreParenImpCasts())) {
568 if (VD == DR->getDecl() && !VD->getType()->isReferenceType()) {
569 Dst.insert(N: Pred);
570 return;
571 }
572 }
573 }
574
575 // FIXME: all pre/post visits should eventually be handled by ::Visit().
576 ExplodedNodeSet dstPreVisit;
577 getCheckerManager().runCheckersForPreStmt(Dst&: dstPreVisit, Src: Pred, S: DS, Eng&: *this);
578
579 ExplodedNodeSet dstEvaluated;
580 for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
581 I!=E; ++I) {
582 ExplodedNode *N = *I;
583 ProgramStateRef state = N->getState();
584 const StackFrame *SF = N->getStackFrame();
585
586 // Decls without InitExpr are not initialized explicitly.
587 if (const Expr *InitEx = VD->getInit()) {
588
589 // Note in the state that the initialization has occurred.
590 ExplodedNode *UpdatedN = N;
591 SVal InitVal = state->getSVal(E: InitEx, SF);
592
593 assert(DS->isSingleDecl());
594 if (getObjectUnderConstruction(State: state, Item: DS, SF)) {
595 state = finishObjectConstruction(State: state, Item: DS, SF);
596 // We constructed the object directly in the variable.
597 // No need to bind anything.
598 dstEvaluated.insert(N: Engine.makePostStmtNode(S: DS, State: state, Pred: UpdatedN));
599 } else {
600 // Recover some path-sensitivity if a scalar value evaluated to
601 // UnknownVal.
602 if (InitVal.isUnknown()) {
603 QualType Ty = InitEx->getType();
604 if (InitEx->isGLValue()) {
605 Ty = getContext().getPointerType(T: Ty);
606 }
607
608 InitVal = svalBuilder.conjureSymbolVal(
609 /*symbolTag=*/nullptr, elem: getCFGElementRef(), SF, type: Ty,
610 count: getNumVisitedCurrent());
611 }
612
613 evalBind(Dst&: dstEvaluated, StoreE: DS, Pred: UpdatedN, location: state->getLValue(VD, SF), Val: InitVal,
614 AtDeclInit: true);
615 }
616 }
617 else {
618 dstEvaluated.insert(N: Engine.makePostStmtNode(S: DS, State: state, Pred: N));
619 }
620 }
621
622 getCheckerManager().runCheckersForPostStmt(Dst, Src: dstEvaluated, S: DS, Eng&: *this);
623}
624
625void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
626 ExplodedNodeSet &Dst) {
627 // This method acts upon CFG elements for logical operators && and ||
628 // and attaches the value (true or false) to them as expressions.
629 // It doesn't produce any state splits.
630 // If we made it that far, we're past the point when we modeled the short
631 // circuit. It means that we should have precise knowledge about whether
632 // we've short-circuited. If we did, we already know the value we need to
633 // bind. If we didn't, the value of the RHS (casted to the boolean type)
634 // is the answer.
635 // Currently this method tries to figure out whether we've short-circuited
636 // by looking at the ExplodedGraph. This method is imperfect because there
637 // could inevitably have been merges that would have resulted in multiple
638 // potential path traversal histories. We bail out when we fail.
639 // Due to this ambiguity, a more reliable solution would have been to
640 // track the short circuit operation history path-sensitively until
641 // we evaluate the respective logical operator.
642 assert(B->getOpcode() == BO_LAnd ||
643 B->getOpcode() == BO_LOr);
644
645 ProgramStateRef state = Pred->getState();
646
647 if (B->getType()->isVectorType()) {
648 // FIXME: We do not model vector arithmetic yet. When adding support for
649 // that, note that the CFG-based reasoning below does not apply, because
650 // logical operators on vectors are not short-circuit. Currently they are
651 // modeled as short-circuit in Clang CFG but this is incorrect.
652 // Do not set the value for the expression. It'd be UnknownVal by default.
653 Dst.insert(N: Engine.makePostStmtNode(S: B, State: state, Pred));
654 return;
655 }
656
657 ExplodedNode *N = Pred;
658 while (!N->getLocation().getAs<BlockEdge>()) {
659 ProgramPoint P = N->getLocation();
660 assert(P.getAs<PreStmt>() || P.getAs<PreStmtPurgeDeadSymbols>() ||
661 P.getAs<BlockEntrance>());
662 (void) P;
663 if (N->pred_size() != 1) {
664 // We failed to track back where we came from.
665 Dst.insert(N: Engine.makePostStmtNode(S: B, State: state, Pred));
666 return;
667 }
668 N = *N->pred_begin();
669 }
670
671 if (N->pred_size() != 1) {
672 // We failed to track back where we came from.
673 Dst.insert(N: Engine.makePostStmtNode(S: B, State: state, Pred));
674 return;
675 }
676
677 BlockEdge BE = N->getLocation().castAs<BlockEdge>();
678 SVal X;
679
680 // Determine the value of the expression by introspecting how we
681 // got this location in the CFG. This requires looking at the previous
682 // block we were in and what kind of control-flow transfer was involved.
683 const CFGBlock *SrcBlock = BE.getSrc();
684 // The only terminator (if there is one) that makes sense is a logical op.
685 CFGTerminator T = SrcBlock->getTerminator();
686 if (const BinaryOperator *Term = cast_or_null<BinaryOperator>(Val: T.getStmt())) {
687 (void) Term;
688 assert(Term->isLogicalOp());
689 assert(SrcBlock->succ_size() == 2);
690 // Did we take the true or false branch?
691 unsigned constant = (*SrcBlock->succ_begin() == BE.getDst()) ? 1 : 0;
692 X = svalBuilder.makeIntVal(integer: constant, type: B->getType());
693 }
694 else {
695 // If there is no terminator, by construction the last statement
696 // in SrcBlock is the value of the enclosing expression.
697 // However, we still need to constrain that value to be 0 or 1.
698 assert(!SrcBlock->empty());
699 CFGStmt Elem = SrcBlock->rbegin()->castAs<CFGStmt>();
700 const Expr *RHS = cast<Expr>(Val: Elem.getStmt());
701 SVal RHSVal = N->getState()->getSVal(E: RHS, SF: Pred->getStackFrame());
702
703 if (RHSVal.isUndef()) {
704 X = RHSVal;
705 } else {
706 // We evaluate "RHSVal != 0" expression which result in 0 if the value is
707 // known to be false, 1 if the value is known to be true and a new symbol
708 // when the assumption is unknown.
709 X = evalBinOp(ST: N->getState(), Op: BO_NE, LHS: RHSVal,
710 RHS: svalBuilder.makeZeroVal(type: RHS->getType()), T: B->getType());
711 }
712 }
713 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: B, V: X));
714}
715
716void ExprEngine::VisitGuardedExpr(const Expr *Ex,
717 const Expr *L,
718 const Expr *R,
719 ExplodedNode *Pred,
720 ExplodedNodeSet &Dst) {
721 assert(L && R);
722
723 ProgramStateRef state = Pred->getState();
724 const StackFrame *SF = Pred->getStackFrame();
725 const CFGBlock *SrcBlock = nullptr;
726
727 // Find the predecessor block.
728 ProgramStateRef SrcState = state;
729 for (const ExplodedNode *N = Pred ; N ; N = *N->pred_begin()) {
730 auto Edge = N->getLocationAs<BlockEdge>();
731 if (!Edge.has_value()) {
732 // If the state N has multiple predecessors P, it means that successors
733 // of P are all equivalent.
734 // In turn, that means that all nodes at P are equivalent in terms
735 // of observable behavior at N, and we can follow any of them.
736 // FIXME: a more robust solution which does not walk up the tree.
737 continue;
738 }
739 SrcBlock = Edge->getSrc();
740 SrcState = N->getState();
741 break;
742 }
743
744 assert(SrcBlock && "missing function entry");
745
746 // Find the last expression in the predecessor block. That is the
747 // expression that is used for the value of the ternary expression.
748 bool hasValue = false;
749 SVal V;
750
751 for (CFGElement CE : llvm::reverse(C: *SrcBlock)) {
752 if (std::optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
753 const Expr *ValEx = cast<Expr>(Val: CS->getStmt());
754 ValEx = ValEx->IgnoreParens();
755
756 // For GNU extension '?:' operator, the left hand side will be an
757 // OpaqueValueExpr, so get the underlying expression.
758 if (const OpaqueValueExpr *OpaqueEx = dyn_cast<OpaqueValueExpr>(Val: L))
759 L = OpaqueEx->getSourceExpr();
760
761 // If the last expression in the predecessor block matches true or false
762 // subexpression, get its the value.
763 if (ValEx == L->IgnoreParens() || ValEx == R->IgnoreParens()) {
764 hasValue = true;
765 V = SrcState->getSVal(E: ValEx, SF);
766 }
767 break;
768 }
769 }
770
771 if (!hasValue)
772 V = svalBuilder.conjureSymbolVal(symbolTag: nullptr, elem: getCFGElementRef(), SF,
773 count: getNumVisitedCurrent());
774
775 // Generate a new node with the binding from the appropriate path.
776 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: Ex, V));
777}
778
779void ExprEngine::VisitOffsetOfExpr(const OffsetOfExpr *OOE, ExplodedNode *Pred,
780 ExplodedNodeSet &Dst) {
781 Expr::EvalResult Result;
782 if (OOE->EvaluateAsInt(Result, Ctx: getContext())) {
783 APSInt IV = Result.Val.getInt();
784 assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
785 assert(OOE->getType()->castAs<BuiltinType>()->isInteger());
786 assert(IV.isSigned() == OOE->getType()->isSignedIntegerType());
787 SVal X = svalBuilder.makeIntVal(integer: IV);
788 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: OOE, V: X));
789 } else {
790 // FIXME: Handle the case where __builtin_offsetof is not a constant.
791 Dst.insert(N: Pred);
792 }
793}
794
795void ExprEngine::VisitUnaryExprOrTypeTraitExpr(
796 const UnaryExprOrTypeTraitExpr *Ex, ExplodedNode *Pred,
797 ExplodedNodeSet &Dst) {
798 QualType T = Ex->getTypeOfArgument();
799
800 if (Ex->getKind() == UETT_SizeOf || Ex->getKind() == UETT_DataSizeOf ||
801 Ex->getKind() == UETT_CountOf) {
802 if (!T->isIncompleteType() && !T->isConstantSizeType()) {
803 assert(T->isVariableArrayType() && "Unknown non-constant-sized type.");
804
805 // FIXME: Add support for VLA type arguments and VLA expressions.
806 // When that happens, we should probably refactor VLASizeChecker's code.
807 Dst.insert(N: Pred);
808 return;
809 } else if (T->getAs<ObjCObjectType>()) {
810 // Some code tries to take the sizeof an ObjCObjectType, relying that
811 // the compiler has laid out its representation. Just report Unknown
812 // for these.
813 Dst.insert(N: Pred);
814 return;
815 }
816 }
817
818 APSInt Value = Ex->EvaluateKnownConstInt(Ctx: getContext());
819 CharUnits amt = CharUnits::fromQuantity(Quantity: Value.getZExtValue());
820
821 SVal V = svalBuilder.makeIntVal(integer: amt.getQuantity(), type: Ex->getType());
822 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: Ex, V));
823}
824
825void ExprEngine::VisitStmtExpr(const StmtExpr *SE, ExplodedNode *Pred,
826 ExplodedNodeSet &Dst) {
827 if (SE->getSubStmt()->body_empty()) {
828 // Empty statement expression.
829 assert(SE->getType() == getContext().VoidTy &&
830 "Empty statement expression must have void type.");
831 } else if (const auto *LastExpr =
832 dyn_cast<Expr>(Val: *SE->getSubStmt()->body_rbegin())) {
833 SVal Val = Pred->getState()->getSVal(E: LastExpr, SF: Pred->getStackFrame());
834 Pred = Engine.makeNodeWithBinding(Pred, E: SE, V: Val);
835 }
836 Dst.insert(N: Pred);
837}
838
839void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
840 ExplodedNodeSet &Dst) {
841 // FIXME: Prechecks eventually go in ::Visit().
842 ExplodedNodeSet CheckedSet;
843 getCheckerManager().runCheckersForPreStmt(Dst&: CheckedSet, Src: Pred, S: U, Eng&: *this);
844
845 ExplodedNodeSet EvalSet;
846
847 // Lambda for handling the case when the operand is returned unchanged.
848 auto MakeNodeForIdentityOp = [U, &Engine = Engine](ExplodedNode *N) {
849 const Expr *Ex = U->getSubExpr()->IgnoreParens();
850 SVal SV = N->getState()->getSVal(E: Ex, SF: N->getStackFrame());
851 return Engine.makeNodeWithBinding(Pred: N, E: U, V: SV);
852 };
853
854 for (ExplodedNode *N : CheckedSet) {
855 switch (U->getOpcode()) {
856 default: {
857 ExplodedNodeSet Tmp;
858 VisitIncrementDecrementOperator(U, Pred: N, Dst&: Tmp);
859 EvalSet.insert(S: Tmp);
860 break;
861 }
862 case UO_Real: {
863 const Expr *Ex = U->getSubExpr()->IgnoreParens();
864
865 // FIXME: We don't have complex SValues yet.
866 if (Ex->getType()->isAnyComplexType()) {
867 // Just report "Unknown."
868 EvalSet.insert(N);
869 break;
870 }
871
872 // For all other types, UO_Real is an identity operation.
873 assert (U->getType() == Ex->getType());
874 EvalSet.insert(N: MakeNodeForIdentityOp(N));
875 break;
876 }
877
878 case UO_Imag: {
879 const Expr *Ex = U->getSubExpr()->IgnoreParens();
880 // FIXME: We don't have complex SValues yet.
881 if (Ex->getType()->isAnyComplexType()) {
882 // Just report "Unknown."
883 EvalSet.insert(N);
884 break;
885 }
886 // For all other types, UO_Imag returns 0.
887 SVal X = svalBuilder.makeZeroVal(type: Ex->getType());
888 EvalSet.insert(N: Engine.makeNodeWithBinding(Pred: N, E: U, V: X));
889 break;
890 }
891
892 case UO_AddrOf: {
893 // Process pointer-to-member address operation.
894 const Expr *Ex = U->getSubExpr()->IgnoreParens();
895 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Val: Ex)) {
896 const ValueDecl *VD = DRE->getDecl();
897
898 if (isa<CXXMethodDecl, FieldDecl, IndirectFieldDecl>(Val: VD)) {
899 SVal SV = svalBuilder.getMemberPointer(ND: cast<NamedDecl>(Val: VD));
900 EvalSet.insert(N: Engine.makeNodeWithBinding(Pred: N, E: U, V: SV));
901 break;
902 }
903 }
904 // Explicitly proceed with default handler for this case cascade.
905 EvalSet.insert(N: MakeNodeForIdentityOp(N));
906 break;
907 }
908 case UO_Plus:
909 assert(!U->isGLValue());
910 [[fallthrough]];
911 case UO_Deref:
912 case UO_Extension: {
913 EvalSet.insert(N: MakeNodeForIdentityOp(N));
914 break;
915 }
916
917 case UO_LNot:
918 case UO_Minus:
919 case UO_Not: {
920 assert (!U->isGLValue());
921 const Expr *Ex = U->getSubExpr()->IgnoreParens();
922 ProgramStateRef state = N->getState();
923 const StackFrame *SF = N->getStackFrame();
924
925 // Get the value of the subexpression.
926 SVal V = state->getSVal(E: Ex, SF);
927
928 if (V.isUnknownOrUndef()) {
929 EvalSet.insert(N: Engine.makeNodeWithBinding(Pred: N, E: U, V));
930 break;
931 }
932
933 switch (U->getOpcode()) {
934 default:
935 llvm_unreachable("Invalid Opcode.");
936 case UO_Not:
937 // FIXME: Do we need to handle promotions?
938 state = state->BindExpr(
939 E: U, SF, V: svalBuilder.evalComplement(val: V.castAs<NonLoc>()));
940 break;
941 case UO_Minus:
942 // FIXME: Do we need to handle promotions?
943 state =
944 state->BindExpr(E: U, SF, V: svalBuilder.evalMinus(val: V.castAs<NonLoc>()));
945 break;
946 case UO_LNot:
947 // C99 6.5.3.3: "The expression !E is equivalent to (0==E)."
948 //
949 // Note: technically we do "E == 0", but this is the same in the
950 // transfer functions as "0 == E".
951 SVal Result;
952 if (std::optional<Loc> LV = V.getAs<Loc>()) {
953 Loc X = svalBuilder.makeNullWithType(type: Ex->getType());
954 Result = evalBinOp(ST: state, Op: BO_EQ, LHS: *LV, RHS: X, T: U->getType());
955 } else if (Ex->getType()->isFloatingType()) {
956 // FIXME: handle floating point types.
957 Result = UnknownVal();
958 } else {
959 nonloc::ConcreteInt X(getBasicVals().getValue(X: 0, T: Ex->getType()));
960 Result = evalBinOp(ST: state, Op: BO_EQ, LHS: V.castAs<NonLoc>(), RHS: X, T: U->getType());
961 }
962
963 state = state->BindExpr(E: U, SF, V: Result);
964 break;
965 }
966 EvalSet.insert(N: Engine.makePostStmtNode(S: U, State: state, Pred: N));
967 break;
968 }
969 }
970 }
971
972 getCheckerManager().runCheckersForPostStmt(Dst, Src: EvalSet, S: U, Eng&: *this);
973}
974
975void ExprEngine::VisitPseudoObjectExpr(const PseudoObjectExpr *PE,
976 ExplodedNode *Pred,
977 ExplodedNodeSet &Dst) {
978 SVal V = UnknownVal();
979 if (const Expr *Result = PE->getResultExpr())
980 V = Pred->getState()->getSVal(E: Result, SF: Pred->getStackFrame());
981 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: PE, V));
982}
983
984void ExprEngine::VisitObjCIndirectCopyRestoreExpr(
985 const ObjCIndirectCopyRestoreExpr *OIE, ExplodedNode *Pred,
986 ExplodedNodeSet &Dst) {
987 // ObjCIndirectCopyRestoreExpr implies passing a temporary for
988 // correctness of lifetime management. Due to limited analysis
989 // of ARC, this is implemented as direct arg passing.
990 const Expr *E = OIE->getSubExpr();
991 SVal V = Pred->getState()->getSVal(E, SF: Pred->getStackFrame());
992 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: OIE, V));
993}
994
995void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
996 ExplodedNode *Pred,
997 ExplodedNodeSet &Dst) {
998 // Handle ++ and -- (both pre- and post-increment).
999 assert (U->isIncrementDecrementOp());
1000 const Expr *Ex = U->getSubExpr()->IgnoreParens();
1001
1002 const StackFrame *SF = Pred->getStackFrame();
1003 ProgramStateRef state = Pred->getState();
1004 SVal loc = state->getSVal(E: Ex, SF);
1005
1006 // Perform a load.
1007 ExplodedNodeSet Tmp;
1008 evalLoad(Dst&: Tmp, NodeEx: U, BoundExpr: Ex, Pred, St: state, location: loc);
1009
1010 ExplodedNodeSet Dst2;
1011 for (ExplodedNode *N : Tmp) {
1012 state = N->getState();
1013 assert(SF == N->getStackFrame());
1014 SVal V2_untested = state->getSVal(E: Ex, SF);
1015
1016 // Propagate unknown and undefined values.
1017 if (V2_untested.isUnknownOrUndef()) {
1018 state = state->BindExpr(E: U, SF, V: V2_untested);
1019
1020 // Perform the store, so that the uninitialized value detection happens.
1021 evalStore(Dst&: Dst2, AssignE: U, StoreE: Ex, Pred: N, St: state, TargetLV: loc, Val: V2_untested);
1022 continue;
1023 }
1024 DefinedSVal V2 = V2_untested.castAs<DefinedSVal>();
1025
1026 // Handle all other values.
1027 BinaryOperator::Opcode Op = U->isIncrementOp() ? BO_Add : BO_Sub;
1028
1029 // If the UnaryOperator has non-location type, use its type to create the
1030 // constant value. If the UnaryOperator has location type, create the
1031 // constant with int type and pointer width.
1032 SVal RHS;
1033 SVal Result;
1034
1035 if (U->getType()->isAnyPointerType())
1036 RHS = svalBuilder.makeArrayIndex(idx: 1);
1037 else if (U->getType()->isIntegralOrEnumerationType())
1038 RHS = svalBuilder.makeIntVal(integer: 1, type: U->getType());
1039 else
1040 RHS = UnknownVal();
1041
1042 // The use of an operand of type bool with the ++ operators is deprecated
1043 // but valid until C++17. And if the operand of the ++ operator is of type
1044 // bool, it is set to true until C++17. Note that for '_Bool', it is also
1045 // set to true when it encounters ++ operator.
1046 if (U->getType()->isBooleanType() && U->isIncrementOp())
1047 Result = svalBuilder.makeTruthVal(b: true, type: U->getType());
1048 else
1049 Result = evalBinOp(ST: state, Op, LHS: V2, RHS, T: U->getType());
1050
1051 // Conjure a new symbol if necessary to recover precision.
1052 if (Result.isUnknown()){
1053 DefinedOrUnknownSVal SymVal = svalBuilder.conjureSymbolVal(
1054 /*symbolTag=*/nullptr, elem: getCFGElementRef(), SF,
1055 count: getNumVisitedCurrent());
1056 Result = SymVal;
1057
1058 // If the value is a location, ++/-- should always preserve
1059 // non-nullness. Check if the original value was non-null, and if so
1060 // propagate that constraint.
1061 if (Loc::isLocType(T: U->getType())) {
1062 DefinedOrUnknownSVal Constraint =
1063 svalBuilder.evalEQ(state, lhs: V2,rhs: svalBuilder.makeZeroVal(type: U->getType()));
1064
1065 if (!state->assume(Cond: Constraint, Assumption: true)) {
1066 // It isn't feasible for the original value to be null.
1067 // Propagate this constraint.
1068 Constraint = svalBuilder.evalEQ(state, lhs: SymVal,
1069 rhs: svalBuilder.makeZeroVal(type: U->getType()));
1070
1071 state = state->assume(Cond: Constraint, Assumption: false);
1072 assert(state);
1073 }
1074 }
1075 }
1076
1077 // Since the lvalue-to-rvalue conversion is explicit in the AST,
1078 // we bind an l-value if the operator is prefix and an lvalue (in C++).
1079 if (U->isGLValue())
1080 state = state->BindExpr(E: U, SF, V: loc);
1081 else
1082 state = state->BindExpr(E: U, SF, V: U->isPostfix() ? V2 : Result);
1083
1084 // Perform the store.
1085 evalStore(Dst&: Dst2, AssignE: U, StoreE: Ex, Pred: N, St: state, TargetLV: loc, Val: Result);
1086 }
1087 Dst.insert(S: Dst2);
1088}
1089