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