diff options
author | Kristof Umann <dkszelethus@gmail.com> | 2018-11-16 01:00:55 +0000 |
---|---|---|
committer | Kristof Umann <dkszelethus@gmail.com> | 2018-11-16 01:00:55 +0000 |
commit | 9d6c4402c667e85eda381b1c0bff11005acaf459 (patch) | |
tree | dcbfeb7e8ad366cccca0fd522167321a31fd7e1e /clang/lib | |
parent | ad9d68c2b44dce12e13bf038f27ba5182b655345 (diff) | |
download | bcm5719-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.cpp | 55 |
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, |