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