summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorKristof Umann <dkszelethus@gmail.com>2018-11-16 01:00:55 +0000
committerKristof Umann <dkszelethus@gmail.com>2018-11-16 01:00:55 +0000
commit9d6c4402c667e85eda381b1c0bff11005acaf459 (patch)
treedcbfeb7e8ad366cccca0fd522167321a31fd7e1e /clang/lib
parentad9d68c2b44dce12e13bf038f27ba5182b655345 (diff)
downloadbcm5719-llvm-9d6c4402c667e85eda381b1c0bff11005acaf459.tar.gz
bcm5719-llvm-9d6c4402c667e85eda381b1c0bff11005acaf459.zip
[analyzer] ConversionChecker: handle floating point
Extend the alpha.core.Conversion checker to handle implicit converions where a too large integer value is converted to a floating point type. Each floating point type has a range where it can exactly represent all integers; we emit a warning when the integer value is above this range. Although it is possible to exactly represent some integers which are outside of this range (those that are divisible by a large enough power of 2); we still report cast involving those, because their usage may lead to bugs. (For example, if 1<<24 is stored in a float variable x, then x==x+1 holds.) Patch by: DonĂ¡t Nagy! Differential Revision: https://reviews.llvm.org/D52730 llvm-svn: 347006
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp55
1 files changed, 45 insertions, 10 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
index 17ec2c28877..208f94451ca 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
@@ -14,8 +14,10 @@
// of expressions. A warning is reported when:
// * a negative value is implicitly converted to an unsigned value in an
// assignment, comparison or multiplication.
-// * assignment / initialization when source value is greater than the max
-// value of target
+// * assignment / initialization when the source value is greater than the max
+// value of the target integer type
+// * assignment / initialization when the source integer is above the range
+// where the target floating point type can represent all integers
//
// Many compilers and tools have similar checks that are based on semantic
// analysis. Those checks are sound but have poor precision. ConversionChecker
@@ -28,6 +30,9 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/ADT/APFloat.h"
+
+#include <climits>
using namespace clang;
using namespace ento;
@@ -40,11 +45,9 @@ public:
private:
mutable std::unique_ptr<BuiltinBug> BT;
- // Is there loss of precision
bool isLossOfPrecision(const ImplicitCastExpr *Cast, QualType DestType,
CheckerContext &C) const;
- // Is there loss of sign
bool isLossOfSign(const ImplicitCastExpr *Cast, CheckerContext &C) const;
void reportBug(ExplodedNode *N, CheckerContext &C, const char Msg[]) const;
@@ -132,19 +135,51 @@ bool ConversionChecker::isLossOfPrecision(const ImplicitCastExpr *Cast,
QualType SubType = Cast->IgnoreParenImpCasts()->getType();
- if (!DestType->isIntegerType() || !SubType->isIntegerType())
+ if (!DestType->isRealType() || !SubType->isIntegerType())
return false;
- if (C.getASTContext().getIntWidth(DestType) >=
- C.getASTContext().getIntWidth(SubType))
+ const bool isFloat = DestType->isFloatingType();
+
+ const auto &AC = C.getASTContext();
+
+ // We will find the largest RepresentsUntilExp value such that the DestType
+ // can exactly represent all nonnegative integers below 2^RepresentsUntilExp.
+ unsigned RepresentsUntilExp;
+
+ if (isFloat) {
+ const llvm::fltSemantics &Sema = AC.getFloatTypeSemantics(DestType);
+ RepresentsUntilExp = llvm::APFloat::semanticsPrecision(Sema);
+ } else {
+ RepresentsUntilExp = AC.getIntWidth(DestType);
+ if (RepresentsUntilExp == 1) {
+ // This is just casting a number to bool, probably not a bug.
+ return false;
+ }
+ if (DestType->isSignedIntegerType())
+ RepresentsUntilExp--;
+ }
+
+ if (RepresentsUntilExp >= sizeof(unsigned long long) * CHAR_BIT) {
+ // Avoid overflow in our later calculations.
return false;
+ }
+
+ unsigned CorrectedSrcWidth = AC.getIntWidth(SubType);
+ if (SubType->isSignedIntegerType())
+ CorrectedSrcWidth--;
- unsigned W = C.getASTContext().getIntWidth(DestType);
- if (W == 1 || W >= 64U)
+ if (RepresentsUntilExp >= CorrectedSrcWidth) {
+ // Simple case: the destination can store all values of the source type.
return false;
+ }
- unsigned long long MaxVal = 1ULL << W;
+ unsigned long long MaxVal = 1ULL << RepresentsUntilExp;
+ if (isFloat) {
+ // If this is a floating point type, it can also represent MaxVal exactly.
+ MaxVal++;
+ }
return C.isGreaterOrEqual(Cast->getSubExpr(), MaxVal);
+ // TODO: maybe also check negative values with too large magnitude.
}
bool ConversionChecker::isLossOfSign(const ImplicitCastExpr *Cast,
OpenPOWER on IntegriCloud