12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097 |
- //===- SValBuilder.cpp - Basic class for all SValBuilder implementations --===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file defines SValBuilder, the base class for all (complete) SValBuilder
- // implementations.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
- #include "clang/AST/ASTContext.h"
- #include "clang/AST/Decl.h"
- #include "clang/AST/DeclCXX.h"
- #include "clang/AST/ExprCXX.h"
- #include "clang/AST/ExprObjC.h"
- #include "clang/AST/Stmt.h"
- #include "clang/AST/Type.h"
- #include "clang/Analysis/AnalysisDeclContext.h"
- #include "clang/Basic/LLVM.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
- #include "llvm/ADT/APSInt.h"
- #include "llvm/Support/Casting.h"
- #include "llvm/Support/Compiler.h"
- #include <cassert>
- #include <optional>
- #include <tuple>
- using namespace clang;
- using namespace ento;
- //===----------------------------------------------------------------------===//
- // Basic SVal creation.
- //===----------------------------------------------------------------------===//
- void SValBuilder::anchor() {}
- SValBuilder::SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
- ProgramStateManager &stateMgr)
- : Context(context), BasicVals(context, alloc),
- SymMgr(context, BasicVals, alloc), MemMgr(context, alloc),
- StateMgr(stateMgr),
- AnOpts(
- stateMgr.getOwningEngine().getAnalysisManager().getAnalyzerOptions()),
- ArrayIndexTy(context.LongLongTy),
- ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {}
- DefinedOrUnknownSVal SValBuilder::makeZeroVal(QualType type) {
- if (Loc::isLocType(type))
- return makeNullWithType(type);
- if (type->isIntegralOrEnumerationType())
- return makeIntVal(0, type);
- if (type->isArrayType() || type->isRecordType() || type->isVectorType() ||
- type->isAnyComplexType())
- return makeCompoundVal(type, BasicVals.getEmptySValList());
- // FIXME: Handle floats.
- return UnknownVal();
- }
- nonloc::SymbolVal SValBuilder::makeNonLoc(const SymExpr *lhs,
- BinaryOperator::Opcode op,
- const llvm::APSInt &rhs,
- QualType type) {
- // The Environment ensures we always get a persistent APSInt in
- // BasicValueFactory, so we don't need to get the APSInt from
- // BasicValueFactory again.
- assert(lhs);
- assert(!Loc::isLocType(type));
- return nonloc::SymbolVal(SymMgr.getSymIntExpr(lhs, op, rhs, type));
- }
- nonloc::SymbolVal SValBuilder::makeNonLoc(const llvm::APSInt &lhs,
- BinaryOperator::Opcode op,
- const SymExpr *rhs, QualType type) {
- assert(rhs);
- assert(!Loc::isLocType(type));
- return nonloc::SymbolVal(SymMgr.getIntSymExpr(lhs, op, rhs, type));
- }
- nonloc::SymbolVal SValBuilder::makeNonLoc(const SymExpr *lhs,
- BinaryOperator::Opcode op,
- const SymExpr *rhs, QualType type) {
- assert(lhs && rhs);
- assert(!Loc::isLocType(type));
- return nonloc::SymbolVal(SymMgr.getSymSymExpr(lhs, op, rhs, type));
- }
- NonLoc SValBuilder::makeNonLoc(const SymExpr *operand, UnaryOperator::Opcode op,
- QualType type) {
- assert(operand);
- assert(!Loc::isLocType(type));
- return nonloc::SymbolVal(SymMgr.getUnarySymExpr(operand, op, type));
- }
- nonloc::SymbolVal SValBuilder::makeNonLoc(const SymExpr *operand,
- QualType fromTy, QualType toTy) {
- assert(operand);
- assert(!Loc::isLocType(toTy));
- if (fromTy == toTy)
- return operand;
- return nonloc::SymbolVal(SymMgr.getCastSymbol(operand, fromTy, toTy));
- }
- SVal SValBuilder::convertToArrayIndex(SVal val) {
- if (val.isUnknownOrUndef())
- return val;
- // Common case: we have an appropriately sized integer.
- if (std::optional<nonloc::ConcreteInt> CI =
- val.getAs<nonloc::ConcreteInt>()) {
- const llvm::APSInt& I = CI->getValue();
- if (I.getBitWidth() == ArrayIndexWidth && I.isSigned())
- return val;
- }
- return evalCast(val, ArrayIndexTy, QualType{});
- }
- nonloc::ConcreteInt SValBuilder::makeBoolVal(const CXXBoolLiteralExpr *boolean){
- return makeTruthVal(boolean->getValue());
- }
- DefinedOrUnknownSVal
- SValBuilder::getRegionValueSymbolVal(const TypedValueRegion *region) {
- QualType T = region->getValueType();
- if (T->isNullPtrType())
- return makeZeroVal(T);
- if (!SymbolManager::canSymbolicate(T))
- return UnknownVal();
- SymbolRef sym = SymMgr.getRegionValueSymbol(region);
- if (Loc::isLocType(T))
- return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
- return nonloc::SymbolVal(sym);
- }
- DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *SymbolTag,
- const Expr *Ex,
- const LocationContext *LCtx,
- unsigned Count) {
- QualType T = Ex->getType();
- if (T->isNullPtrType())
- return makeZeroVal(T);
- // Compute the type of the result. If the expression is not an R-value, the
- // result should be a location.
- QualType ExType = Ex->getType();
- if (Ex->isGLValue())
- T = LCtx->getAnalysisDeclContext()->getASTContext().getPointerType(ExType);
- return conjureSymbolVal(SymbolTag, Ex, LCtx, T, Count);
- }
- DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag,
- const Expr *expr,
- const LocationContext *LCtx,
- QualType type,
- unsigned count) {
- if (type->isNullPtrType())
- return makeZeroVal(type);
- if (!SymbolManager::canSymbolicate(type))
- return UnknownVal();
- SymbolRef sym = SymMgr.conjureSymbol(expr, LCtx, type, count, symbolTag);
- if (Loc::isLocType(type))
- return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
- return nonloc::SymbolVal(sym);
- }
- DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const Stmt *stmt,
- const LocationContext *LCtx,
- QualType type,
- unsigned visitCount) {
- if (type->isNullPtrType())
- return makeZeroVal(type);
- if (!SymbolManager::canSymbolicate(type))
- return UnknownVal();
- SymbolRef sym = SymMgr.conjureSymbol(stmt, LCtx, type, visitCount);
- if (Loc::isLocType(type))
- return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
- return nonloc::SymbolVal(sym);
- }
- DefinedOrUnknownSVal
- SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
- const LocationContext *LCtx,
- unsigned VisitCount) {
- QualType T = E->getType();
- return getConjuredHeapSymbolVal(E, LCtx, T, VisitCount);
- }
- DefinedOrUnknownSVal
- SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
- const LocationContext *LCtx,
- QualType type, unsigned VisitCount) {
- assert(Loc::isLocType(type));
- assert(SymbolManager::canSymbolicate(type));
- if (type->isNullPtrType())
- return makeZeroVal(type);
- SymbolRef sym = SymMgr.conjureSymbol(E, LCtx, type, VisitCount);
- return loc::MemRegionVal(MemMgr.getSymbolicHeapRegion(sym));
- }
- DefinedSVal SValBuilder::getMetadataSymbolVal(const void *symbolTag,
- const MemRegion *region,
- const Expr *expr, QualType type,
- const LocationContext *LCtx,
- unsigned count) {
- assert(SymbolManager::canSymbolicate(type) && "Invalid metadata symbol type");
- SymbolRef sym =
- SymMgr.getMetadataSymbol(region, expr, type, LCtx, count, symbolTag);
- if (Loc::isLocType(type))
- return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
- return nonloc::SymbolVal(sym);
- }
- DefinedOrUnknownSVal
- SValBuilder::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
- const TypedValueRegion *region) {
- QualType T = region->getValueType();
- if (T->isNullPtrType())
- return makeZeroVal(T);
- if (!SymbolManager::canSymbolicate(T))
- return UnknownVal();
- SymbolRef sym = SymMgr.getDerivedSymbol(parentSymbol, region);
- if (Loc::isLocType(T))
- return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
- return nonloc::SymbolVal(sym);
- }
- DefinedSVal SValBuilder::getMemberPointer(const NamedDecl *ND) {
- assert(!ND || (isa<CXXMethodDecl, FieldDecl, IndirectFieldDecl>(ND)));
- if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(ND)) {
- // Sema treats pointers to static member functions as have function pointer
- // type, so return a function pointer for the method.
- // We don't need to play a similar trick for static member fields
- // because these are represented as plain VarDecls and not FieldDecls
- // in the AST.
- if (MD->isStatic())
- return getFunctionPointer(MD);
- }
- return nonloc::PointerToMember(ND);
- }
- DefinedSVal SValBuilder::getFunctionPointer(const FunctionDecl *func) {
- return loc::MemRegionVal(MemMgr.getFunctionCodeRegion(func));
- }
- DefinedSVal SValBuilder::getBlockPointer(const BlockDecl *block,
- CanQualType locTy,
- const LocationContext *locContext,
- unsigned blockCount) {
- const BlockCodeRegion *BC =
- MemMgr.getBlockCodeRegion(block, locTy, locContext->getAnalysisDeclContext());
- const BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, locContext,
- blockCount);
- return loc::MemRegionVal(BD);
- }
- std::optional<loc::MemRegionVal>
- SValBuilder::getCastedMemRegionVal(const MemRegion *R, QualType Ty) {
- if (auto OptR = StateMgr.getStoreManager().castRegion(R, Ty))
- return loc::MemRegionVal(*OptR);
- return std::nullopt;
- }
- /// Return a memory region for the 'this' object reference.
- loc::MemRegionVal SValBuilder::getCXXThis(const CXXMethodDecl *D,
- const StackFrameContext *SFC) {
- return loc::MemRegionVal(
- getRegionManager().getCXXThisRegion(D->getThisType(), SFC));
- }
- /// Return a memory region for the 'this' object reference.
- loc::MemRegionVal SValBuilder::getCXXThis(const CXXRecordDecl *D,
- const StackFrameContext *SFC) {
- const Type *T = D->getTypeForDecl();
- QualType PT = getContext().getPointerType(QualType(T, 0));
- return loc::MemRegionVal(getRegionManager().getCXXThisRegion(PT, SFC));
- }
- std::optional<SVal> SValBuilder::getConstantVal(const Expr *E) {
- E = E->IgnoreParens();
- switch (E->getStmtClass()) {
- // Handle expressions that we treat differently from the AST's constant
- // evaluator.
- case Stmt::AddrLabelExprClass:
- return makeLoc(cast<AddrLabelExpr>(E));
- case Stmt::CXXScalarValueInitExprClass:
- case Stmt::ImplicitValueInitExprClass:
- return makeZeroVal(E->getType());
- case Stmt::ObjCStringLiteralClass: {
- const auto *SL = cast<ObjCStringLiteral>(E);
- return makeLoc(getRegionManager().getObjCStringRegion(SL));
- }
- case Stmt::StringLiteralClass: {
- const auto *SL = cast<StringLiteral>(E);
- return makeLoc(getRegionManager().getStringRegion(SL));
- }
- case Stmt::PredefinedExprClass: {
- const auto *PE = cast<PredefinedExpr>(E);
- assert(PE->getFunctionName() &&
- "Since we analyze only instantiated functions, PredefinedExpr "
- "should have a function name.");
- return makeLoc(getRegionManager().getStringRegion(PE->getFunctionName()));
- }
- // Fast-path some expressions to avoid the overhead of going through the AST's
- // constant evaluator
- case Stmt::CharacterLiteralClass: {
- const auto *C = cast<CharacterLiteral>(E);
- return makeIntVal(C->getValue(), C->getType());
- }
- case Stmt::CXXBoolLiteralExprClass:
- return makeBoolVal(cast<CXXBoolLiteralExpr>(E));
- case Stmt::TypeTraitExprClass: {
- const auto *TE = cast<TypeTraitExpr>(E);
- return makeTruthVal(TE->getValue(), TE->getType());
- }
- case Stmt::IntegerLiteralClass:
- return makeIntVal(cast<IntegerLiteral>(E));
- case Stmt::ObjCBoolLiteralExprClass:
- return makeBoolVal(cast<ObjCBoolLiteralExpr>(E));
- case Stmt::CXXNullPtrLiteralExprClass:
- return makeNullWithType(E->getType());
- case Stmt::CStyleCastExprClass:
- case Stmt::CXXFunctionalCastExprClass:
- case Stmt::CXXConstCastExprClass:
- case Stmt::CXXReinterpretCastExprClass:
- case Stmt::CXXStaticCastExprClass:
- case Stmt::ImplicitCastExprClass: {
- const auto *CE = cast<CastExpr>(E);
- switch (CE->getCastKind()) {
- default:
- break;
- case CK_ArrayToPointerDecay:
- case CK_IntegralToPointer:
- case CK_NoOp:
- case CK_BitCast: {
- const Expr *SE = CE->getSubExpr();
- std::optional<SVal> Val = getConstantVal(SE);
- if (!Val)
- return std::nullopt;
- return evalCast(*Val, CE->getType(), SE->getType());
- }
- }
- // FALLTHROUGH
- [[fallthrough]];
- }
- // If we don't have a special case, fall back to the AST's constant evaluator.
- default: {
- // Don't try to come up with a value for materialized temporaries.
- if (E->isGLValue())
- return std::nullopt;
- ASTContext &Ctx = getContext();
- Expr::EvalResult Result;
- if (E->EvaluateAsInt(Result, Ctx))
- return makeIntVal(Result.Val.getInt());
- if (Loc::isLocType(E->getType()))
- if (E->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
- return makeNullWithType(E->getType());
- return std::nullopt;
- }
- }
- }
- SVal SValBuilder::makeSymExprValNN(BinaryOperator::Opcode Op,
- NonLoc LHS, NonLoc RHS,
- QualType ResultTy) {
- SymbolRef symLHS = LHS.getAsSymbol();
- SymbolRef symRHS = RHS.getAsSymbol();
- // TODO: When the Max Complexity is reached, we should conjure a symbol
- // instead of generating an Unknown value and propagate the taint info to it.
- const unsigned MaxComp = AnOpts.MaxSymbolComplexity;
- if (symLHS && symRHS &&
- (symLHS->computeComplexity() + symRHS->computeComplexity()) < MaxComp)
- return makeNonLoc(symLHS, Op, symRHS, ResultTy);
- if (symLHS && symLHS->computeComplexity() < MaxComp)
- if (std::optional<nonloc::ConcreteInt> rInt =
- RHS.getAs<nonloc::ConcreteInt>())
- return makeNonLoc(symLHS, Op, rInt->getValue(), ResultTy);
- if (symRHS && symRHS->computeComplexity() < MaxComp)
- if (std::optional<nonloc::ConcreteInt> lInt =
- LHS.getAs<nonloc::ConcreteInt>())
- return makeNonLoc(lInt->getValue(), Op, symRHS, ResultTy);
- return UnknownVal();
- }
- SVal SValBuilder::evalMinus(NonLoc X) {
- switch (X.getSubKind()) {
- case nonloc::ConcreteIntKind:
- return makeIntVal(-X.castAs<nonloc::ConcreteInt>().getValue());
- case nonloc::SymbolValKind:
- return makeNonLoc(X.castAs<nonloc::SymbolVal>().getSymbol(), UO_Minus,
- X.getType(Context));
- default:
- return UnknownVal();
- }
- }
- SVal SValBuilder::evalComplement(NonLoc X) {
- switch (X.getSubKind()) {
- case nonloc::ConcreteIntKind:
- return makeIntVal(~X.castAs<nonloc::ConcreteInt>().getValue());
- case nonloc::SymbolValKind:
- return makeNonLoc(X.castAs<nonloc::SymbolVal>().getSymbol(), UO_Not,
- X.getType(Context));
- default:
- return UnknownVal();
- }
- }
- SVal SValBuilder::evalUnaryOp(ProgramStateRef state, UnaryOperator::Opcode opc,
- SVal operand, QualType type) {
- auto OpN = operand.getAs<NonLoc>();
- if (!OpN)
- return UnknownVal();
- if (opc == UO_Minus)
- return evalMinus(*OpN);
- if (opc == UO_Not)
- return evalComplement(*OpN);
- llvm_unreachable("Unexpected unary operator");
- }
- SVal SValBuilder::evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
- SVal lhs, SVal rhs, QualType type) {
- if (lhs.isUndef() || rhs.isUndef())
- return UndefinedVal();
- if (lhs.isUnknown() || rhs.isUnknown())
- return UnknownVal();
- if (isa<nonloc::LazyCompoundVal>(lhs) || isa<nonloc::LazyCompoundVal>(rhs)) {
- return UnknownVal();
- }
- if (op == BinaryOperatorKind::BO_Cmp) {
- // We can't reason about C++20 spaceship operator yet.
- //
- // FIXME: Support C++20 spaceship operator.
- // The main problem here is that the result is not integer.
- return UnknownVal();
- }
- if (std::optional<Loc> LV = lhs.getAs<Loc>()) {
- if (std::optional<Loc> RV = rhs.getAs<Loc>())
- return evalBinOpLL(state, op, *LV, *RV, type);
- return evalBinOpLN(state, op, *LV, rhs.castAs<NonLoc>(), type);
- }
- if (const std::optional<Loc> RV = rhs.getAs<Loc>()) {
- const auto IsCommutative = [](BinaryOperatorKind Op) {
- return Op == BO_Mul || Op == BO_Add || Op == BO_And || Op == BO_Xor ||
- Op == BO_Or;
- };
- if (IsCommutative(op)) {
- // Swap operands.
- return evalBinOpLN(state, op, *RV, lhs.castAs<NonLoc>(), type);
- }
- // If the right operand is a concrete int location then we have nothing
- // better but to treat it as a simple nonloc.
- if (auto RV = rhs.getAs<loc::ConcreteInt>()) {
- const nonloc::ConcreteInt RhsAsLoc = makeIntVal(RV->getValue());
- return evalBinOpNN(state, op, lhs.castAs<NonLoc>(), RhsAsLoc, type);
- }
- }
- return evalBinOpNN(state, op, lhs.castAs<NonLoc>(), rhs.castAs<NonLoc>(),
- type);
- }
- ConditionTruthVal SValBuilder::areEqual(ProgramStateRef state, SVal lhs,
- SVal rhs) {
- return state->isNonNull(evalEQ(state, lhs, rhs));
- }
- SVal SValBuilder::evalEQ(ProgramStateRef state, SVal lhs, SVal rhs) {
- return evalBinOp(state, BO_EQ, lhs, rhs, getConditionType());
- }
- DefinedOrUnknownSVal SValBuilder::evalEQ(ProgramStateRef state,
- DefinedOrUnknownSVal lhs,
- DefinedOrUnknownSVal rhs) {
- return evalEQ(state, static_cast<SVal>(lhs), static_cast<SVal>(rhs))
- .castAs<DefinedOrUnknownSVal>();
- }
- /// Recursively check if the pointer types are equal modulo const, volatile,
- /// and restrict qualifiers. Also, assume that all types are similar to 'void'.
- /// Assumes the input types are canonical.
- static bool shouldBeModeledWithNoOp(ASTContext &Context, QualType ToTy,
- QualType FromTy) {
- while (Context.UnwrapSimilarTypes(ToTy, FromTy)) {
- Qualifiers Quals1, Quals2;
- ToTy = Context.getUnqualifiedArrayType(ToTy, Quals1);
- FromTy = Context.getUnqualifiedArrayType(FromTy, Quals2);
- // Make sure that non-cvr-qualifiers the other qualifiers (e.g., address
- // spaces) are identical.
- Quals1.removeCVRQualifiers();
- Quals2.removeCVRQualifiers();
- if (Quals1 != Quals2)
- return false;
- }
- // If we are casting to void, the 'From' value can be used to represent the
- // 'To' value.
- //
- // FIXME: Doing this after unwrapping the types doesn't make any sense. A
- // cast from 'int**' to 'void**' is not special in the way that a cast from
- // 'int*' to 'void*' is.
- if (ToTy->isVoidType())
- return true;
- if (ToTy != FromTy)
- return false;
- return true;
- }
- // Handles casts of type CK_IntegralCast.
- // At the moment, this function will redirect to evalCast, except when the range
- // of the original value is known to be greater than the max of the target type.
- SVal SValBuilder::evalIntegralCast(ProgramStateRef state, SVal val,
- QualType castTy, QualType originalTy) {
- // No truncations if target type is big enough.
- if (getContext().getTypeSize(castTy) >= getContext().getTypeSize(originalTy))
- return evalCast(val, castTy, originalTy);
- SymbolRef se = val.getAsSymbol();
- if (!se) // Let evalCast handle non symbolic expressions.
- return evalCast(val, castTy, originalTy);
- // Find the maximum value of the target type.
- APSIntType ToType(getContext().getTypeSize(castTy),
- castTy->isUnsignedIntegerType());
- llvm::APSInt ToTypeMax = ToType.getMaxValue();
- NonLoc ToTypeMaxVal =
- makeIntVal(ToTypeMax.isUnsigned() ? ToTypeMax.getZExtValue()
- : ToTypeMax.getSExtValue(),
- castTy)
- .castAs<NonLoc>();
- // Check the range of the symbol being casted against the maximum value of the
- // target type.
- NonLoc FromVal = val.castAs<NonLoc>();
- QualType CmpTy = getConditionType();
- NonLoc CompVal =
- evalBinOpNN(state, BO_LE, FromVal, ToTypeMaxVal, CmpTy).castAs<NonLoc>();
- ProgramStateRef IsNotTruncated, IsTruncated;
- std::tie(IsNotTruncated, IsTruncated) = state->assume(CompVal);
- if (!IsNotTruncated && IsTruncated) {
- // Symbol is truncated so we evaluate it as a cast.
- return makeNonLoc(se, originalTy, castTy);
- }
- return evalCast(val, castTy, originalTy);
- }
- //===----------------------------------------------------------------------===//
- // Cast method.
- // `evalCast` and its helper `EvalCastVisitor`
- //===----------------------------------------------------------------------===//
- namespace {
- class EvalCastVisitor : public SValVisitor<EvalCastVisitor, SVal> {
- private:
- SValBuilder &VB;
- ASTContext &Context;
- QualType CastTy, OriginalTy;
- public:
- EvalCastVisitor(SValBuilder &VB, QualType CastTy, QualType OriginalTy)
- : VB(VB), Context(VB.getContext()), CastTy(CastTy),
- OriginalTy(OriginalTy) {}
- SVal Visit(SVal V) {
- if (CastTy.isNull())
- return V;
- CastTy = Context.getCanonicalType(CastTy);
- const bool IsUnknownOriginalType = OriginalTy.isNull();
- if (!IsUnknownOriginalType) {
- OriginalTy = Context.getCanonicalType(OriginalTy);
- if (CastTy == OriginalTy)
- return V;
- // FIXME: Move this check to the most appropriate
- // evalCastKind/evalCastSubKind function. For const casts, casts to void,
- // just propagate the value.
- if (!CastTy->isVariableArrayType() && !OriginalTy->isVariableArrayType())
- if (shouldBeModeledWithNoOp(Context, Context.getPointerType(CastTy),
- Context.getPointerType(OriginalTy)))
- return V;
- }
- return SValVisitor::Visit(V);
- }
- SVal VisitUndefinedVal(UndefinedVal V) { return V; }
- SVal VisitUnknownVal(UnknownVal V) { return V; }
- SVal VisitLocConcreteInt(loc::ConcreteInt V) {
- // Pointer to bool.
- if (CastTy->isBooleanType())
- return VB.makeTruthVal(V.getValue().getBoolValue(), CastTy);
- // Pointer to integer.
- if (CastTy->isIntegralOrEnumerationType()) {
- llvm::APSInt Value = V.getValue();
- VB.getBasicValueFactory().getAPSIntType(CastTy).apply(Value);
- return VB.makeIntVal(Value);
- }
- // Pointer to any pointer.
- if (Loc::isLocType(CastTy)) {
- llvm::APSInt Value = V.getValue();
- VB.getBasicValueFactory().getAPSIntType(CastTy).apply(Value);
- return loc::ConcreteInt(VB.getBasicValueFactory().getValue(Value));
- }
- // Pointer to whatever else.
- return UnknownVal();
- }
- SVal VisitLocGotoLabel(loc::GotoLabel V) {
- // Pointer to bool.
- if (CastTy->isBooleanType())
- // Labels are always true.
- return VB.makeTruthVal(true, CastTy);
- // Pointer to integer.
- if (CastTy->isIntegralOrEnumerationType()) {
- const unsigned BitWidth = Context.getIntWidth(CastTy);
- return VB.makeLocAsInteger(V, BitWidth);
- }
- const bool IsUnknownOriginalType = OriginalTy.isNull();
- if (!IsUnknownOriginalType) {
- // Array to pointer.
- if (isa<ArrayType>(OriginalTy))
- if (CastTy->isPointerType() || CastTy->isReferenceType())
- return UnknownVal();
- }
- // Pointer to any pointer.
- if (Loc::isLocType(CastTy))
- return V;
- // Pointer to whatever else.
- return UnknownVal();
- }
- SVal VisitLocMemRegionVal(loc::MemRegionVal V) {
- // Pointer to bool.
- if (CastTy->isBooleanType()) {
- const MemRegion *R = V.getRegion();
- if (const FunctionCodeRegion *FTR = dyn_cast<FunctionCodeRegion>(R))
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(FTR->getDecl()))
- if (FD->isWeak())
- // FIXME: Currently we are using an extent symbol here,
- // because there are no generic region address metadata
- // symbols to use, only content metadata.
- return nonloc::SymbolVal(
- VB.getSymbolManager().getExtentSymbol(FTR));
- if (const SymbolicRegion *SymR = R->getSymbolicBase()) {
- SymbolRef Sym = SymR->getSymbol();
- QualType Ty = Sym->getType();
- // This change is needed for architectures with varying
- // pointer widths. See the amdgcn opencl reproducer with
- // this change as an example: solver-sym-simplification-ptr-bool.cl
- if (!Ty->isReferenceType())
- return VB.makeNonLoc(
- Sym, BO_NE, VB.getBasicValueFactory().getZeroWithTypeSize(Ty),
- CastTy);
- }
- // Non-symbolic memory regions are always true.
- return VB.makeTruthVal(true, CastTy);
- }
- const bool IsUnknownOriginalType = OriginalTy.isNull();
- // Try to cast to array
- const auto *ArrayTy =
- IsUnknownOriginalType
- ? nullptr
- : dyn_cast<ArrayType>(OriginalTy.getCanonicalType());
- // Pointer to integer.
- if (CastTy->isIntegralOrEnumerationType()) {
- SVal Val = V;
- // Array to integer.
- if (ArrayTy) {
- // We will always decay to a pointer.
- QualType ElemTy = ArrayTy->getElementType();
- Val = VB.getStateManager().ArrayToPointer(V, ElemTy);
- // FIXME: Keep these here for now in case we decide soon that we
- // need the original decayed type.
- // QualType elemTy = cast<ArrayType>(originalTy)->getElementType();
- // QualType pointerTy = C.getPointerType(elemTy);
- }
- const unsigned BitWidth = Context.getIntWidth(CastTy);
- return VB.makeLocAsInteger(Val.castAs<Loc>(), BitWidth);
- }
- // Pointer to pointer.
- if (Loc::isLocType(CastTy)) {
- if (IsUnknownOriginalType) {
- // When retrieving symbolic pointer and expecting a non-void pointer,
- // wrap them into element regions of the expected type if necessary.
- // It is necessary to make sure that the retrieved value makes sense,
- // because there's no other cast in the AST that would tell us to cast
- // it to the correct pointer type. We might need to do that for non-void
- // pointers as well.
- // FIXME: We really need a single good function to perform casts for us
- // correctly every time we need it.
- const MemRegion *R = V.getRegion();
- if (CastTy->isPointerType() && !CastTy->isVoidPointerType()) {
- if (const auto *SR = dyn_cast<SymbolicRegion>(R)) {
- QualType SRTy = SR->getSymbol()->getType();
- auto HasSameUnqualifiedPointeeType = [](QualType ty1,
- QualType ty2) {
- return ty1->getPointeeType().getCanonicalType().getTypePtr() ==
- ty2->getPointeeType().getCanonicalType().getTypePtr();
- };
- if (!HasSameUnqualifiedPointeeType(SRTy, CastTy)) {
- if (auto OptMemRegV = VB.getCastedMemRegionVal(SR, CastTy))
- return *OptMemRegV;
- }
- }
- }
- // Next fixes pointer dereference using type different from its initial
- // one. See PR37503 and PR49007 for details.
- if (const auto *ER = dyn_cast<ElementRegion>(R)) {
- if (auto OptMemRegV = VB.getCastedMemRegionVal(ER, CastTy))
- return *OptMemRegV;
- }
- return V;
- }
- if (OriginalTy->isIntegralOrEnumerationType() ||
- OriginalTy->isBlockPointerType() ||
- OriginalTy->isFunctionPointerType())
- return V;
- // Array to pointer.
- if (ArrayTy) {
- // Are we casting from an array to a pointer? If so just pass on
- // the decayed value.
- if (CastTy->isPointerType() || CastTy->isReferenceType()) {
- // We will always decay to a pointer.
- QualType ElemTy = ArrayTy->getElementType();
- return VB.getStateManager().ArrayToPointer(V, ElemTy);
- }
- // Are we casting from an array to an integer? If so, cast the decayed
- // pointer value to an integer.
- assert(CastTy->isIntegralOrEnumerationType());
- }
- // Other pointer to pointer.
- assert(Loc::isLocType(OriginalTy) || OriginalTy->isFunctionType() ||
- CastTy->isReferenceType());
- // We get a symbolic function pointer for a dereference of a function
- // pointer, but it is of function type. Example:
- // struct FPRec {
- // void (*my_func)(int * x);
- // };
- //
- // int bar(int x);
- //
- // int f1_a(struct FPRec* foo) {
- // int x;
- // (*foo->my_func)(&x);
- // return bar(x)+1; // no-warning
- // }
- // Get the result of casting a region to a different type.
- const MemRegion *R = V.getRegion();
- if (auto OptMemRegV = VB.getCastedMemRegionVal(R, CastTy))
- return *OptMemRegV;
- }
- // Pointer to whatever else.
- // FIXME: There can be gross cases where one casts the result of a
- // function (that returns a pointer) to some other value that happens to
- // fit within that pointer value. We currently have no good way to model
- // such operations. When this happens, the underlying operation is that
- // the caller is reasoning about bits. Conceptually we are layering a
- // "view" of a location on top of those bits. Perhaps we need to be more
- // lazy about mutual possible views, even on an SVal? This may be
- // necessary for bit-level reasoning as well.
- return UnknownVal();
- }
- SVal VisitNonLocCompoundVal(nonloc::CompoundVal V) {
- // Compound to whatever.
- return UnknownVal();
- }
- SVal VisitNonLocConcreteInt(nonloc::ConcreteInt V) {
- auto CastedValue = [V, this]() {
- llvm::APSInt Value = V.getValue();
- VB.getBasicValueFactory().getAPSIntType(CastTy).apply(Value);
- return Value;
- };
- // Integer to bool.
- if (CastTy->isBooleanType())
- return VB.makeTruthVal(V.getValue().getBoolValue(), CastTy);
- // Integer to pointer.
- if (CastTy->isIntegralOrEnumerationType())
- return VB.makeIntVal(CastedValue());
- // Integer to pointer.
- if (Loc::isLocType(CastTy))
- return VB.makeIntLocVal(CastedValue());
- // Pointer to whatever else.
- return UnknownVal();
- }
- SVal VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal V) {
- // LazyCompound to whatever.
- return UnknownVal();
- }
- SVal VisitNonLocLocAsInteger(nonloc::LocAsInteger V) {
- Loc L = V.getLoc();
- // Pointer as integer to bool.
- if (CastTy->isBooleanType())
- // Pass to Loc function.
- return Visit(L);
- const bool IsUnknownOriginalType = OriginalTy.isNull();
- // Pointer as integer to pointer.
- if (!IsUnknownOriginalType && Loc::isLocType(CastTy) &&
- OriginalTy->isIntegralOrEnumerationType()) {
- if (const MemRegion *R = L.getAsRegion())
- if (auto OptMemRegV = VB.getCastedMemRegionVal(R, CastTy))
- return *OptMemRegV;
- return L;
- }
- // Pointer as integer with region to integer/pointer.
- const MemRegion *R = L.getAsRegion();
- if (!IsUnknownOriginalType && R) {
- if (CastTy->isIntegralOrEnumerationType())
- return VisitLocMemRegionVal(loc::MemRegionVal(R));
- if (Loc::isLocType(CastTy)) {
- assert(Loc::isLocType(OriginalTy) || OriginalTy->isFunctionType() ||
- CastTy->isReferenceType());
- // Delegate to store manager to get the result of casting a region to a
- // different type. If the MemRegion* returned is NULL, this expression
- // Evaluates to UnknownVal.
- if (auto OptMemRegV = VB.getCastedMemRegionVal(R, CastTy))
- return *OptMemRegV;
- }
- } else {
- if (Loc::isLocType(CastTy)) {
- if (IsUnknownOriginalType)
- return VisitLocMemRegionVal(loc::MemRegionVal(R));
- return L;
- }
- SymbolRef SE = nullptr;
- if (R) {
- if (const SymbolicRegion *SR =
- dyn_cast<SymbolicRegion>(R->StripCasts())) {
- SE = SR->getSymbol();
- }
- }
- if (!CastTy->isFloatingType() || !SE || SE->getType()->isFloatingType()) {
- // FIXME: Correctly support promotions/truncations.
- const unsigned CastSize = Context.getIntWidth(CastTy);
- if (CastSize == V.getNumBits())
- return V;
- return VB.makeLocAsInteger(L, CastSize);
- }
- }
- // Pointer as integer to whatever else.
- return UnknownVal();
- }
- SVal VisitNonLocSymbolVal(nonloc::SymbolVal V) {
- SymbolRef SE = V.getSymbol();
- const bool IsUnknownOriginalType = OriginalTy.isNull();
- // Symbol to bool.
- if (!IsUnknownOriginalType && CastTy->isBooleanType()) {
- // Non-float to bool.
- if (Loc::isLocType(OriginalTy) ||
- OriginalTy->isIntegralOrEnumerationType() ||
- OriginalTy->isMemberPointerType()) {
- BasicValueFactory &BVF = VB.getBasicValueFactory();
- return VB.makeNonLoc(SE, BO_NE, BVF.getValue(0, SE->getType()), CastTy);
- }
- } else {
- // Symbol to integer, float.
- QualType T = Context.getCanonicalType(SE->getType());
- // Produce SymbolCast if CastTy and T are different integers.
- // NOTE: In the end the type of SymbolCast shall be equal to CastTy.
- if (T->isIntegralOrUnscopedEnumerationType() &&
- CastTy->isIntegralOrUnscopedEnumerationType()) {
- AnalyzerOptions &Opts = VB.getStateManager()
- .getOwningEngine()
- .getAnalysisManager()
- .getAnalyzerOptions();
- // If appropriate option is disabled, ignore the cast.
- // NOTE: ShouldSupportSymbolicIntegerCasts is `false` by default.
- if (!Opts.ShouldSupportSymbolicIntegerCasts)
- return V;
- return simplifySymbolCast(V, CastTy);
- }
- if (!Loc::isLocType(CastTy))
- if (!IsUnknownOriginalType || !CastTy->isFloatingType() ||
- T->isFloatingType())
- return VB.makeNonLoc(SE, T, CastTy);
- }
- // Symbol to pointer and whatever else.
- return UnknownVal();
- }
- SVal VisitNonLocPointerToMember(nonloc::PointerToMember V) {
- // Member pointer to whatever.
- return V;
- }
- /// Reduce cast expression by removing redundant intermediate casts.
- /// E.g.
- /// - (char)(short)(int x) -> (char)(int x)
- /// - (int)(int x) -> int x
- ///
- /// \param V -- SymbolVal, which pressumably contains SymbolCast or any symbol
- /// that is applicable for cast operation.
- /// \param CastTy -- QualType, which `V` shall be cast to.
- /// \return SVal with simplified cast expression.
- /// \note: Currently only support integral casts.
- nonloc::SymbolVal simplifySymbolCast(nonloc::SymbolVal V, QualType CastTy) {
- // We use seven conditions to recognize a simplification case.
- // For the clarity let `CastTy` be `C`, SE->getType() - `T`, root type -
- // `R`, prefix `u` for unsigned, `s` for signed, no prefix - any sign: E.g.
- // (char)(short)(uint x)
- // ( sC )( sT )( uR x)
- //
- // C === R (the same type)
- // (char)(char x) -> (char x)
- // (long)(long x) -> (long x)
- // Note: Comparisons operators below are for bit width.
- // C == T
- // (short)(short)(int x) -> (short)(int x)
- // (int)(long)(char x) -> (int)(char x) (sizeof(long) == sizeof(int))
- // (long)(ullong)(char x) -> (long)(char x) (sizeof(long) ==
- // sizeof(ullong))
- // C < T
- // (short)(int)(char x) -> (short)(char x)
- // (char)(int)(short x) -> (char)(short x)
- // (short)(int)(short x) -> (short x)
- // C > T > uR
- // (int)(short)(uchar x) -> (int)(uchar x)
- // (uint)(short)(uchar x) -> (uint)(uchar x)
- // (int)(ushort)(uchar x) -> (int)(uchar x)
- // C > sT > sR
- // (int)(short)(char x) -> (int)(char x)
- // (uint)(short)(char x) -> (uint)(char x)
- // C > sT == sR
- // (int)(char)(char x) -> (int)(char x)
- // (uint)(short)(short x) -> (uint)(short x)
- // C > uT == uR
- // (int)(uchar)(uchar x) -> (int)(uchar x)
- // (uint)(ushort)(ushort x) -> (uint)(ushort x)
- // (llong)(ulong)(uint x) -> (llong)(uint x) (sizeof(ulong) ==
- // sizeof(uint))
- SymbolRef SE = V.getSymbol();
- QualType T = Context.getCanonicalType(SE->getType());
- if (T == CastTy)
- return V;
- if (!isa<SymbolCast>(SE))
- return VB.makeNonLoc(SE, T, CastTy);
- SymbolRef RootSym = cast<SymbolCast>(SE)->getOperand();
- QualType RT = RootSym->getType().getCanonicalType();
- // FIXME support simplification from non-integers.
- if (!RT->isIntegralOrEnumerationType())
- return VB.makeNonLoc(SE, T, CastTy);
- BasicValueFactory &BVF = VB.getBasicValueFactory();
- APSIntType CTy = BVF.getAPSIntType(CastTy);
- APSIntType TTy = BVF.getAPSIntType(T);
- const auto WC = CTy.getBitWidth();
- const auto WT = TTy.getBitWidth();
- if (WC <= WT) {
- const bool isSameType = (RT == CastTy);
- if (isSameType)
- return nonloc::SymbolVal(RootSym);
- return VB.makeNonLoc(RootSym, RT, CastTy);
- }
- APSIntType RTy = BVF.getAPSIntType(RT);
- const auto WR = RTy.getBitWidth();
- const bool UT = TTy.isUnsigned();
- const bool UR = RTy.isUnsigned();
- if (((WT > WR) && (UR || !UT)) || ((WT == WR) && (UT == UR)))
- return VB.makeNonLoc(RootSym, RT, CastTy);
- return VB.makeNonLoc(SE, T, CastTy);
- }
- };
- } // end anonymous namespace
- /// Cast a given SVal to another SVal using given QualType's.
- /// \param V -- SVal that should be casted.
- /// \param CastTy -- QualType that V should be casted according to.
- /// \param OriginalTy -- QualType which is associated to V. It provides
- /// additional information about what type the cast performs from.
- /// \returns the most appropriate casted SVal.
- /// Note: Many cases don't use an exact OriginalTy. It can be extracted
- /// from SVal or the cast can performs unconditionaly. Always pass OriginalTy!
- /// It can be crucial in certain cases and generates different results.
- /// FIXME: If `OriginalTy.isNull()` is true, then cast performs based on CastTy
- /// only. This behavior is uncertain and should be improved.
- SVal SValBuilder::evalCast(SVal V, QualType CastTy, QualType OriginalTy) {
- EvalCastVisitor TRV{*this, CastTy, OriginalTy};
- return TRV.Visit(V);
- }
|