clang 20.0.0git
ExprEngineC.cpp
Go to the documentation of this file.
1//=-- ExprEngineC.cpp - ExprEngine support for C expressions ----*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines ExprEngine's support for C expressions.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/AST/DeclCXX.h"
14#include "clang/AST/ExprCXX.h"
17#include <optional>
18
19using namespace clang;
20using namespace ento;
21using llvm::APSInt;
22
23/// Optionally conjure and return a symbol for offset when processing
24/// an expression \p Expression.
25/// If \p Other is a location, conjure a symbol for \p Symbol
26/// (offset) if it is unknown so that memory arithmetic always
27/// results in an ElementRegion.
28/// \p Count The number of times the current basic block was visited.
30 SVal Symbol, SVal Other, Expr* Expression, SValBuilder &svalBuilder,
31 unsigned Count, const LocationContext *LCtx) {
32 QualType Ty = Expression->getType();
33 if (isa<Loc>(Other) && Ty->isIntegralOrEnumerationType() &&
34 Symbol.isUnknown()) {
35 return svalBuilder.conjureSymbolVal(Expression, LCtx, Ty, Count);
36 }
37 return Symbol;
38}
39
41 ExplodedNode *Pred,
42 ExplodedNodeSet &Dst) {
43
44 Expr *LHS = B->getLHS()->IgnoreParens();
45 Expr *RHS = B->getRHS()->IgnoreParens();
46
47 // FIXME: Prechecks eventually go in ::Visit().
48 ExplodedNodeSet CheckedSet;
49 ExplodedNodeSet Tmp2;
50 getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, B, *this);
51
52 // With both the LHS and RHS evaluated, process the operation itself.
53 for (ExplodedNodeSet::iterator it=CheckedSet.begin(), ei=CheckedSet.end();
54 it != ei; ++it) {
55
56 ProgramStateRef state = (*it)->getState();
57 const LocationContext *LCtx = (*it)->getLocationContext();
58 SVal LeftV = state->getSVal(LHS, LCtx);
59 SVal RightV = state->getSVal(RHS, LCtx);
60
62
63 if (Op == BO_Assign) {
64 // EXPERIMENTAL: "Conjured" symbols.
65 // FIXME: Handle structs.
66 if (RightV.isUnknown()) {
67 unsigned Count = currBldrCtx->blockCount();
68 RightV = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx,
69 Count);
70 }
71 // Simulate the effects of a "store": bind the value of the RHS
72 // to the L-Value represented by the LHS.
73 SVal ExprVal = B->isGLValue() ? LeftV : RightV;
74 evalStore(Tmp2, B, LHS, *it, state->BindExpr(B, LCtx, ExprVal),
75 LeftV, RightV);
76 continue;
77 }
78
79 if (!B->isAssignmentOp()) {
80 StmtNodeBuilder Bldr(*it, Tmp2, *currBldrCtx);
81
82 if (B->isAdditiveOp()) {
83 // TODO: This can be removed after we enable history tracking with
84 // SymSymExpr.
85 unsigned Count = currBldrCtx->blockCount();
87 RightV, LeftV, RHS, svalBuilder, Count, LCtx);
89 LeftV, RightV, LHS, svalBuilder, Count, LCtx);
90 }
91
92 // Although we don't yet model pointers-to-members, we do need to make
93 // sure that the members of temporaries have a valid 'this' pointer for
94 // other checks.
95 if (B->getOpcode() == BO_PtrMemD)
96 state = createTemporaryRegionIfNeeded(state, LCtx, LHS);
97
98 // Process non-assignments except commas or short-circuited
99 // logical expressions (LAnd and LOr).
100 SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType());
101 if (!Result.isUnknown()) {
102 state = state->BindExpr(B, LCtx, Result);
103 } else {
104 // If we cannot evaluate the operation escape the operands.
105 state = escapeValues(state, LeftV, PSK_EscapeOther);
106 state = escapeValues(state, RightV, PSK_EscapeOther);
107 }
108
109 Bldr.generateNode(B, *it, state);
110 continue;
111 }
112
113 assert (B->isCompoundAssignmentOp());
114
115 switch (Op) {
116 default:
117 llvm_unreachable("Invalid opcode for compound assignment.");
118 case BO_MulAssign: Op = BO_Mul; break;
119 case BO_DivAssign: Op = BO_Div; break;
120 case BO_RemAssign: Op = BO_Rem; break;
121 case BO_AddAssign: Op = BO_Add; break;
122 case BO_SubAssign: Op = BO_Sub; break;
123 case BO_ShlAssign: Op = BO_Shl; break;
124 case BO_ShrAssign: Op = BO_Shr; break;
125 case BO_AndAssign: Op = BO_And; break;
126 case BO_XorAssign: Op = BO_Xor; break;
127 case BO_OrAssign: Op = BO_Or; break;
128 }
129
130 // Perform a load (the LHS). This performs the checks for
131 // null dereferences, and so on.
132 ExplodedNodeSet Tmp;
133 SVal location = LeftV;
134 evalLoad(Tmp, B, LHS, *it, state, location);
135
136 for (ExplodedNode *N : Tmp) {
137 state = N->getState();
138 const LocationContext *LCtx = N->getLocationContext();
139 SVal V = state->getSVal(LHS, LCtx);
140
141 // Get the computation type.
142 QualType CTy =
143 cast<CompoundAssignOperator>(B)->getComputationResultType();
144 CTy = getContext().getCanonicalType(CTy);
145
146 QualType CLHSTy =
147 cast<CompoundAssignOperator>(B)->getComputationLHSType();
148 CLHSTy = getContext().getCanonicalType(CLHSTy);
149
151
152 // Promote LHS.
153 V = svalBuilder.evalCast(V, CLHSTy, LTy);
154
155 // Compute the result of the operation.
156 SVal Result = svalBuilder.evalCast(evalBinOp(state, Op, V, RightV, CTy),
157 B->getType(), CTy);
158
159 // EXPERIMENTAL: "Conjured" symbols.
160 // FIXME: Handle structs.
161
162 SVal LHSVal;
163
164 if (Result.isUnknown()) {
165 // The symbolic value is actually for the type of the left-hand side
166 // expression, not the computation type, as this is the value the
167 // LValue on the LHS will bind to.
168 LHSVal = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx, LTy,
169 currBldrCtx->blockCount());
170 // However, we need to convert the symbol to the computation type.
171 Result = svalBuilder.evalCast(LHSVal, CTy, LTy);
172 } else {
173 // The left-hand side may bind to a different value then the
174 // computation type.
175 LHSVal = svalBuilder.evalCast(Result, LTy, CTy);
176 }
177
178 // In C++, assignment and compound assignment operators return an
179 // lvalue.
180 if (B->isGLValue())
181 state = state->BindExpr(B, LCtx, location);
182 else
183 state = state->BindExpr(B, LCtx, Result);
184
185 evalStore(Tmp2, B, LHS, N, state, location, LHSVal);
186 }
187 }
188
189 // FIXME: postvisits eventually go in ::Visit()
190 getCheckerManager().runCheckersForPostStmt(Dst, Tmp2, B, *this);
191}
192
194 ExplodedNodeSet &Dst) {
195
197
198 const BlockDecl *BD = BE->getBlockDecl();
199 // Get the value of the block itself.
200 SVal V = svalBuilder.getBlockPointer(BD, T,
201 Pred->getLocationContext(),
202 currBldrCtx->blockCount());
203
204 ProgramStateRef State = Pred->getState();
205
206 // If we created a new MemRegion for the block, we should explicitly bind
207 // the captured variables.
208 if (const BlockDataRegion *BDR =
209 dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) {
210
211 auto ReferencedVars = BDR->referenced_vars();
212 auto CI = BD->capture_begin();
213 auto CE = BD->capture_end();
214 for (auto Var : ReferencedVars) {
215 const VarRegion *capturedR = Var.getCapturedRegion();
216 const