aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h86
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h39
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp46
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)