diff options
3 files changed, 120 insertions, 51 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h new file mode 100644 index 0000000000..dcb77792ff --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h @@ -0,0 +1,86 @@ +//== APSIntType.h - Simple record of the type of APSInts --------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SA_CORE_APSINTTYPE_H +#define LLVM_CLANG_SA_CORE_APSINTTYPE_H + +#include "llvm/ADT/APSInt.h" + +namespace clang { +namespace ento { + +/// \brief A record of the "type" of an APSInt, used for conversions. +class APSIntType { + uint32_t BitWidth; + bool IsUnsigned; + +public: + APSIntType(uint32_t Width, bool Unsigned) + : BitWidth(Width), IsUnsigned(Unsigned) {} + + /* implicit */ APSIntType(const llvm::APSInt &Value) + : BitWidth(Value.getBitWidth()), IsUnsigned(Value.isUnsigned()) {} + + uint32_t getBitWidth() const { return BitWidth; } + bool isUnsigned() const { return IsUnsigned; } + + /// \brief Convert a given APSInt, in place, to match this type. + /// + /// This behaves like a C cast: converting 255u8 (0xFF) to s16 gives + /// 255 (0x00FF), and converting -1s8 (0xFF) to u16 gives 65535 (0xFFFF). + void apply(llvm::APSInt &Value) const { + // Note the order here. We extend first to preserve the sign, if this value + // is signed, /then/ match the signedness of the result type. + Value = Value.extOrTrunc(BitWidth); + Value.setIsUnsigned(IsUnsigned); + } + + /// Convert and return a new APSInt with the given value, but this + /// type's bit width and signedness. + /// + /// \see apply + llvm::APSInt convert(const llvm::APSInt &Value) const LLVM_READONLY { + llvm::APSInt Result(Value, Value.isUnsigned()); + apply(Result); + return Result; + } + + /// Returns the minimum value for this type. + llvm::APSInt getMinValue() const LLVM_READONLY { + return llvm::APSInt::getMinValue(BitWidth, IsUnsigned); + } + + /// Returns the maximum value for this type. + llvm::APSInt getMaxValue() const LLVM_READONLY { + return llvm::APSInt::getMaxValue(BitWidth, IsUnsigned); + } + + bool operator==(const APSIntType &Other) const { + return BitWidth == Other.BitWidth && IsUnsigned == Other.IsUnsigned; + } + + /// \brief Provide an ordering for finding a common conversion type. + /// + /// Unsigned integers are considered to be better conversion types than + /// signed integers of the same width. + bool operator<(const APSIntType &Other) const { + if (BitWidth < Other.BitWidth) + return true; + if (BitWidth > Other.BitWidth) + return false; + if (!IsUnsigned && Other.IsUnsigned) + return true; + return false; + } +}; + +} // end ento namespace +} // end clang namespace + +#endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h index 9a699f9b7c..b4a9de76f4 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h @@ -16,6 +16,7 @@ #ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H #define LLVM_CLANG_GR_BASICVALUEFACTORY_H +#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" @@ -86,28 +87,30 @@ public: const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned); const llvm::APSInt& getValue(uint64_t X, QualType T); + /// Returns the type of the APSInt used to store values of the given QualType. + APSIntType getAPSIntType(QualType T) const { + assert(T->isIntegerType() || Loc::isLocType(T)); + return APSIntType(Ctx.getTypeSize(T), + !T->isSignedIntegerOrEnumerationType()); + } + /// Convert - Create a new persistent APSInt with the same value as 'From' /// but with the bitwidth and signedness of 'To'. const llvm::APSInt &Convert(const llvm::APSInt& To, const llvm::APSInt& From) { - - if (To.isUnsigned() == From.isUnsigned() && - To.getBitWidth() == From.getBitWidth()) + APSIntType TargetType(To); + if (TargetType == APSIntType(From)) return From; - return getValue(From.getSExtValue(), To.getBitWidth(), To.isUnsigned()); + return getValue(TargetType.convert(From)); } const llvm::APSInt &Convert(QualType T, const llvm::APSInt &From) { - assert(T->isIntegerType() || Loc::isLocType(T)); - unsigned bitwidth = Ctx.getTypeSize(T); - bool isUnsigned - = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T); - - if (isUnsigned == From.isUnsigned() && bitwidth == From.getBitWidth()) + APSIntType TargetType = getAPSIntType(T); + if (TargetType == APSIntType(From)) return From; - return getValue(From.getSExtValue(), bitwidth, isUnsigned); + return getValue(TargetType.convert(From)); } const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) { @@ -116,25 +119,19 @@ public: } inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) { - return getValue(llvm::APSInt::getMaxValue(v.getBitWidth(), v.isUnsigned())); + return getValue(APSIntType(v).getMaxValue()); } inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) { - return getValue(llvm::APSInt::getMinValue(v.getBitWidth(), v.isUnsigned())); + return getValue(APSIntType(v).getMinValue()); } inline const llvm::APSInt& getMaxValue(QualType T) { - assert(T->isIntegerType() || Loc::isLocType(T)); - bool isUnsigned - = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T); - return getValue(llvm::APSInt::getMaxValue(Ctx.getTypeSize(T), isUnsigned)); + return getValue(getAPSIntType(T).getMaxValue()); } inline const llvm::APSInt& getMinValue(QualType T) { - assert(T->isIntegerType() || Loc::isLocType(T)); - bool isUnsigned - = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T); - return getValue(llvm::APSInt::getMinValue(Ctx.getTypeSize(T), isUnsigned)); + return getValue(getAPSIntType(T).getMinValue()); } inline const llvm::APSInt& Add1(const llvm::APSInt& V) { diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index 9c5590bf1c..2e37be0c6b 100644 --- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" @@ -106,9 +107,7 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) { return UnknownVal(); llvm::APSInt i = cast<nonloc::ConcreteInt>(val).getValue(); - i.setIsUnsigned(castTy->isUnsignedIntegerOrEnumerationType() || - Loc::isLocType(castTy)); - i = i.extOrTrunc(Context.getTypeSize(castTy)); + BasicVals.getAPSIntType(castTy).apply(i); if (isLocType) return makeIntLocVal(i); @@ -139,9 +138,7 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) { return makeLocAsInteger(val, BitWidth); llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue(); - i.setIsUnsigned(castTy->isUnsignedIntegerOrEnumerationType() || - Loc::isLocType(castTy)); - i = i.extOrTrunc(BitWidth); + BasicVals.getAPSIntType(castTy).apply(i); return makeIntVal(i); } @@ -341,8 +338,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, case nonloc::ConcreteIntKind: { // Transform the integer into a location and compare. llvm::APSInt i = cast<nonloc::ConcreteInt>(rhs).getValue(); - i.setIsUnsigned(true); - i = i.extOrTrunc(Context.getTypeSize(Context.VoidPtrTy)); + BasicVals.getAPSIntType(Context.VoidPtrTy).apply(i); return evalBinOpLL(state, op, lhsL, makeLoc(i), resultTy); } default: @@ -365,23 +361,16 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, llvm::APSInt RHSValue = *KnownRHSValue; if (BinaryOperator::isComparisonOp(op)) { // We're looking for a type big enough to compare the two values. - uint32_t LeftWidth = LHSValue.getBitWidth(); - uint32_t RightWidth = RHSValue.getBitWidth(); - - // Based on the conversion rules of [C99 6.3.1.8] and the example - // in SemaExpr's handleIntegerConversion(). - if (LeftWidth > RightWidth) - RHSValue = RHSValue.extend(LeftWidth); - else if (LeftWidth < RightWidth) - LHSValue = LHSValue.extend(RightWidth); - else if (LHSValue.isUnsigned() != RHSValue.isUnsigned()) { - LHSValue.setIsUnsigned(true); - RHSValue.setIsUnsigned(true); - } + // FIXME: This is not correct. char + short will result in a promotion + // to int. Unfortunately we have lost types by this point. + APSIntType CompareType = std::max(APSIntType(LHSValue), + APSIntType(RHSValue)); + CompareType.apply(LHSValue); + CompareType.apply(RHSValue); } else if (!BinaryOperator::isShiftOp(op)) { - // FIXME: These values don't need to be persistent. - LHSValue = BasicVals.Convert(resultTy, LHSValue); - RHSValue = BasicVals.Convert(resultTy, RHSValue); + APSIntType IntType = BasicVals.getAPSIntType(resultTy); + IntType.apply(LHSValue); + IntType.apply(RHSValue); } const llvm::APSInt *Result = @@ -490,12 +479,9 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, // (such as x+1U+2LL). The rules for implicit conversions should // choose a reasonable type to preserve the expression, and will // at least match how the value is going to be used. - - // FIXME: These values don't need to be persistent. - const llvm::APSInt &first = - BasicVals.Convert(resultTy, symIntExpr->getRHS()); - const llvm::APSInt &second = - BasicVals.Convert(resultTy, *RHSValue); + APSIntType IntType = BasicVals.getAPSIntType(resultTy); + const llvm::APSInt &first = IntType.convert(symIntExpr->getRHS()); + const llvm::APSInt &second = IntType.convert(*RHSValue); const llvm::APSInt *newRHS; if (lop == op) |