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