2009-07-21 21:03:30 +00:00
|
|
|
// SValuator.cpp - Basic class for all SValuator implementations --*- C++ -*--//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file defines SValuator, the base class for all (complete) SValuator
|
|
|
|
// implementations.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang/Analysis/PathSensitive/SValuator.h"
|
|
|
|
#include "clang/Analysis/PathSensitive/GRState.h"
|
|
|
|
|
|
|
|
using namespace clang;
|
|
|
|
|
2009-08-25 18:44:25 +00:00
|
|
|
|
|
|
|
SVal SValuator::EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op,
|
|
|
|
SVal L, SVal R, QualType T) {
|
|
|
|
|
|
|
|
if (L.isUndef() || R.isUndef())
|
|
|
|
return UndefinedVal();
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-08-25 18:44:25 +00:00
|
|
|
if (L.isUnknown() || R.isUnknown())
|
|
|
|
return UnknownVal();
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-08-25 18:44:25 +00:00
|
|
|
if (isa<Loc>(L)) {
|
|
|
|
if (isa<Loc>(R))
|
|
|
|
return EvalBinOpLL(Op, cast<Loc>(L), cast<Loc>(R), T);
|
|
|
|
|
|
|
|
return EvalBinOpLN(ST, Op, cast<Loc>(L), cast<NonLoc>(R), T);
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-08-25 18:44:25 +00:00
|
|
|
if (isa<Loc>(R)) {
|
|
|
|
// Support pointer arithmetic where the increment/decrement operand
|
2009-09-09 15:08:12 +00:00
|
|
|
// is on the left and the pointer on the right.
|
2009-08-25 18:44:25 +00:00
|
|
|
assert(Op == BinaryOperator::Add || Op == BinaryOperator::Sub);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-08-25 18:44:25 +00:00
|
|
|
// Commute the operands.
|
|
|
|
return EvalBinOpLN(ST, Op, cast<Loc>(R), cast<NonLoc>(L), T);
|
|
|
|
}
|
|
|
|
|
2009-10-06 01:39:48 +00:00
|
|
|
return EvalBinOpNN(ST, Op, cast<NonLoc>(L), cast<NonLoc>(R), T);
|
2009-08-25 18:44:25 +00:00
|
|
|
}
|
|
|
|
|
2009-09-11 22:07:28 +00:00
|
|
|
DefinedOrUnknownSVal SValuator::EvalEQ(const GRState *ST,
|
|
|
|
DefinedOrUnknownSVal L,
|
|
|
|
DefinedOrUnknownSVal R) {
|
|
|
|
return cast<DefinedOrUnknownSVal>(EvalBinOp(ST, BinaryOperator::EQ, L, R,
|
|
|
|
ValMgr.getContext().IntTy));
|
|
|
|
}
|
|
|
|
|
2009-09-09 15:08:12 +00:00
|
|
|
SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
|
2009-07-21 21:03:30 +00:00
|
|
|
QualType castTy, QualType originalTy){
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-21 21:03:30 +00:00
|
|
|
if (val.isUnknownOrUndef() || castTy == originalTy)
|
|
|
|
return CastResult(state, val);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-21 21:03:30 +00:00
|
|
|
ASTContext &C = ValMgr.getContext();
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-21 21:03:30 +00:00
|
|
|
// For const casts, just propagate the value.
|
First part of changes to eliminate problems with cv-qualifiers and
sugared types. The basic problem is that our qualifier accessors
(getQualifiers, getCVRQualifiers, isConstQualified, etc.) only look at
the current QualType and not at any qualifiers that come from sugared
types, meaning that we won't see these qualifiers through, e.g.,
typedefs:
typedef const int CInt;
typedef CInt Self;
Self.isConstQualified() currently returns false!
Various bugs (e.g., PR5383) have cropped up all over the front end due
to such problems. I'm addressing this problem by splitting each
qualifier accessor into two versions:
- the "local" version only returns qualifiers on this particular
QualType instance
- the "normal" version that will eventually combine qualifiers from this
QualType instance with the qualifiers on the canonical type to
produce the full set of qualifiers.
This commit adds the local versions and switches a few callers from
the "normal" version (e.g., isConstQualified) over to the "local"
version (e.g., isLocalConstQualified) when that is the right thing to
do, e.g., because we're printing or serializing the qualifiers. Also,
switch a bunch of
Context.getCanonicalType(T1).getUnqualifiedType() == Context.getCanonicalType(T2).getQualifiedType()
expressions over to
Context.hasSameUnqualifiedType(T1, T2)
llvm-svn: 88969
2009-11-16 21:35:15 +00:00
|
|
|
if (C.hasSameUnqualifiedType(castTy, originalTy))
|
2009-07-21 21:03:30 +00:00
|
|
|
return CastResult(state, val);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-21 21:03:30 +00:00
|
|
|
// Check for casts from pointers to integers.
|
|
|
|
if (castTy->isIntegerType() && Loc::IsLocType(originalTy))
|
|
|
|
return CastResult(state, EvalCastL(cast<Loc>(val), castTy));
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-21 21:03:30 +00:00
|
|
|
// Check for casts from integers to pointers.
|
|
|
|
if (Loc::IsLocType(castTy) && originalTy->isIntegerType()) {
|
|
|
|
if (nonloc::LocAsInteger *LV = dyn_cast<nonloc::LocAsInteger>(&val)) {
|
|
|
|
// Just unpackage the lval and return it.
|
|
|
|
return CastResult(state, LV->getLoc());
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-21 21:03:30 +00:00
|
|
|
goto DispatchCast;
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-21 21:03:30 +00:00
|
|
|
// Just pass through function and block pointers.
|
|
|
|
if (originalTy->isBlockPointerType() || originalTy->isFunctionPointerType()) {
|
|
|
|
assert(Loc::IsLocType(castTy));
|
|
|
|
return CastResult(state, val);
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-21 21:03:30 +00:00
|
|
|
// Check for casts from array type to another type.
|
|
|
|
if (originalTy->isArrayType()) {
|
|
|
|
// We will always decay to a pointer.
|
|
|
|
val = ValMgr.getStateManager().ArrayToPointer(cast<Loc>(val));
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-21 21:03:30 +00:00
|
|
|
// Are we casting from an array to a pointer? If so just pass on
|
|
|
|
// the decayed value.
|
|
|
|
if (castTy->isPointerType())
|
|
|
|
return CastResult(state, val);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-21 21:03:30 +00:00
|
|
|
// Are we casting from an array to an integer? If so, cast the decayed
|
|
|
|
// pointer value to an integer.
|
|
|
|
assert(castTy->isIntegerType());
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-21 21:03:30 +00:00
|
|
|
// 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);
|
|
|
|
return CastResult(state, EvalCastL(cast<Loc>(val), castTy));
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-21 21:03:30 +00:00
|
|
|
// Check for casts from a region to a specific type.
|
|
|
|
if (const MemRegion *R = val.getAsRegion()) {
|
|
|
|
// FIXME: We should handle the case where we strip off view layers to get
|
|
|
|
// to a desugared type.
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-21 21:03:30 +00:00
|
|
|
assert(Loc::IsLocType(castTy));
|
|
|
|
// We get a symbolic function pointer for a dereference of a function
|
|
|
|
// pointer, but it is of function type. Example:
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-21 21:03:30 +00:00
|
|
|
// struct FPRec {
|
2009-09-09 15:08:12 +00:00
|
|
|
// void (*my_func)(int * x);
|
2009-07-21 21:03:30 +00:00
|
|
|
// };
|
|
|
|
//
|
|
|
|
// int bar(int x);
|
|
|
|
//
|
|
|
|
// int f1_a(struct FPRec* foo) {
|
|
|
|
// int x;
|
|
|
|
// (*foo->my_func)(&x);
|
|
|
|
// return bar(x)+1; // no-warning
|
|
|
|
// }
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-21 21:03:30 +00:00
|
|
|
assert(Loc::IsLocType(originalTy) || originalTy->isFunctionType() ||
|
|
|
|
originalTy->isBlockPointerType());
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-21 21:03:30 +00:00
|
|
|
StoreManager &storeMgr = ValMgr.getStateManager().getStoreManager();
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-10-14 06:55:01 +00:00
|
|
|
// 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.
|
|
|
|
R = storeMgr.CastRegion(R, castTy);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-21 21:03:30 +00:00
|
|
|
if (R)
|
2009-10-14 06:55:01 +00:00
|
|
|
return CastResult(state, loc::MemRegionVal(R));
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-10-14 06:55:01 +00:00
|
|
|
return CastResult(state, UnknownVal());
|
2009-07-21 21:03:30 +00:00
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
|
|
|
// All other cases.
|
2009-07-21 21:03:30 +00:00
|
|
|
DispatchCast:
|
|
|
|
return CastResult(state,
|
2009-09-09 15:08:12 +00:00
|
|
|
isa<Loc>(val) ? EvalCastL(cast<Loc>(val), castTy)
|
2009-07-21 21:03:30 +00:00
|
|
|
: EvalCastNL(cast<NonLoc>(val), castTy));
|
2009-07-24 23:12:58 +00:00
|
|
|
}
|
2009-09-11 22:07:28 +00:00
|
|
|
|
|
|
|
SValuator::DefinedOrUnknownCastResult
|
|
|
|
SValuator::EvalCast(DefinedOrUnknownSVal V, const GRState *ST,
|
|
|
|
QualType castTy, QualType originalType) {
|
|
|
|
SValuator::CastResult X = EvalCast((SVal) V, ST, castTy, originalType);
|
|
|
|
return DefinedOrUnknownCastResult(X.getState(),
|
|
|
|
cast<DefinedOrUnknownSVal>(X.getSVal()));
|
|
|
|
}
|