Skip to content

Commit 8e0d456

Browse files
committed
Give long double literals out of the range of double no value
Review of the previous commit: a long double literal larger than double, such as 1e400L, became a known value of infinity, so different literals compared equal and gave false positives: 1e400L / 1e500L duplicateExpression x == 1e400L || x == 1e500L knownConditionTrueFalse x > 1e400L && x < 1e500L incorrectLogicOperator Infinity is right for literals without suffix or with f (HUGE_VAL), not for long double. MathLib::isLongDoubleOutOfDoubleRange() tells them apart; ValueFlow gives such a literal no value and CheckCondition does not compare it.
1 parent 6cdcde1 commit 8e0d456

7 files changed

Lines changed: 58 additions & 6 deletions

File tree

‎lib/checkcondition.cpp‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,6 +1301,10 @@ void CheckConditionImpl::checkIncorrectLogicOperator()
13011301
if (isfloat && (op1 == "==" || op1 == "!=" || op2 == "==" || op2 == "!="))
13021302
continue;
13031303

1304+
// no double value to compare (1e400L would become infinity)
1305+
if (isfloat && (MathLib::isLongDoubleOutOfDoubleRange(value1) || MathLib::isLongDoubleOutOfDoubleRange(value2)))
1306+
continue;
1307+
13041308
// the expr are not the token of the value but they provide better context
13051309
const double d1 = isfloat ? MathLib::toDoubleNumber(value1) : 0;
13061310
const double d2 = isfloat ? MathLib::toDoubleNumber(value2) : 0;

‎lib/mathlib.cpp‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,13 @@ bool MathLib::isFloat(const std::string &str)
591591
return isDecimalFloat(str) || isFloatHex(str);
592592
}
593593

594+
bool MathLib::isLongDoubleOutOfDoubleRange(const std::string &str)
595+
{
596+
if (str.empty() || (str.back() != 'l' && str.back() != 'L') || !isFloat(str))
597+
return false;
598+
return std::isinf(toDoubleNumber(str));
599+
}
600+
594601
bool MathLib::isDecimalFloat(const std::string &str)
595602
{
596603
if (str.empty())

‎lib/mathlib.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ class CPPCHECKLIB MathLib {
115115

116116
static bool isInt(const std::string & str);
117117
static bool isFloat(const std::string &str);
118+
/** @brief a long double literal out of the range of double, such as 1e400L, which toDoubleNumber() makes infinity */
119+
static bool isLongDoubleOutOfDoubleRange(const std::string &str);
118120
static bool isDecimalFloat(const std::string &str);
119121
static bool isNegative(const std::string &str);
120122
static bool isPositive(const std::string &str);

‎lib/vf_common.cpp‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,16 @@ namespace ValueFlow
139139
// Bad character literal
140140
}
141141
} else if (tok->isNumber() && MathLib::isFloat(tok->str())) {
142-
Value value;
143-
value.valueType = Value::ValueType::FLOAT;
144-
value.floatValue = MathLib::toDoubleNumber(tok);
145-
if (!tok->isTemplateArg())
146-
value.setKnown();
147-
setTokenValue(tok, std::move(value), settings);
142+
// A long double literal out of the range of double (1e400L) has no
143+
// double value: infinity would make different literals compare equal.
144+
if (!MathLib::isLongDoubleOutOfDoubleRange(tok->str())) {
145+
Value value;
146+
value.valueType = Value::ValueType::FLOAT;
147+
value.floatValue = MathLib::toDoubleNumber(tok);
148+
if (!tok->isTemplateArg())
149+
value.setKnown();
150+
setTokenValue(tok, std::move(value), settings);
151+
}
148152
} else if (tok->enumerator() && tok->enumerator()->value_known) {
149153
Value value(tok->enumerator()->value);
150154
if (!tok->isTemplateArg())

‎test/testcondition.cpp‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class TestCondition : public TestFixture {
6969
TEST_CASE(incorrectLogicOperator15);
7070
TEST_CASE(incorrectLogicOperator16); // #10070
7171
TEST_CASE(incorrectLogicOperator17);
72+
TEST_CASE(incorrectLogicOperator18); // #12282
7273
TEST_CASE(secondAlwaysTrueFalseWhenFirstTrueError);
7374
TEST_CASE(incorrectLogicOp_condSwapping);
7475
TEST_CASE(testBug5895);
@@ -1758,6 +1759,17 @@ class TestCondition : public TestFixture {
17581759
ASSERT_EQUALS("", errout_str());
17591760
}
17601761

1762+
void incorrectLogicOperator18() { // #12282
1763+
// long double literals out of the range of double are different values
1764+
check("int f(long double x) {\n"
1765+
" return x > 1e400L && x < 1e500L;\n"
1766+
"}\n"
1767+
"int g() {\n"
1768+
" return 1e400L < 1e500L;\n"
1769+
"}\n");
1770+
ASSERT_EQUALS("", errout_str());
1771+
}
1772+
17611773
void incorrectLogicOperator17() { // #12471
17621774
check("struct R {\n"
17631775
" void set() { i = 1; }\n"

‎test/testmathlib.cpp‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class TestMathLib : public TestFixture {
4545
TEST_CASE(isnegative);
4646
TEST_CASE(ispositive);
4747
TEST_CASE(isFloat);
48+
TEST_CASE(isLongDoubleOutOfDoubleRange);
4849
TEST_CASE(isDecimalFloat);
4950
TEST_CASE(isGreater);
5051
TEST_CASE(isGreaterEqual);
@@ -599,6 +600,16 @@ class TestMathLib : public TestFixture {
599600
// TODO: test with 128-bit values
600601
}
601602

603+
void isLongDoubleOutOfDoubleRange() const {
604+
ASSERT_EQUALS(true, MathLib::isLongDoubleOutOfDoubleRange("1e400L"));
605+
ASSERT_EQUALS(true, MathLib::isLongDoubleOutOfDoubleRange("1.0e4931l"));
606+
ASSERT_EQUALS(false, MathLib::isLongDoubleOutOfDoubleRange("1e300L"));
607+
ASSERT_EQUALS(false, MathLib::isLongDoubleOutOfDoubleRange("1e10000"));
608+
ASSERT_EQUALS(false, MathLib::isLongDoubleOutOfDoubleRange("1e10000f"));
609+
ASSERT_EQUALS(false, MathLib::isLongDoubleOutOfDoubleRange("10L"));
610+
ASSERT_EQUALS(false, MathLib::isLongDoubleOutOfDoubleRange(""));
611+
}
612+
602613
void toDoubleNumber() const {
603614
// float values
604615
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1."), 0.001);

‎test/testother.cpp‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ class TestOther : public TestFixture {
204204
TEST_CASE(duplicateExpression20);
205205
TEST_CASE(duplicateExpression21);
206206
TEST_CASE(duplicateExpression22);
207+
TEST_CASE(duplicateExpression23); // #12282
207208
TEST_CASE(duplicateExpressionLoop);
208209
TEST_CASE(duplicateValueTernary);
209210
TEST_CASE(duplicateValueTernarySizeof); // #13773
@@ -8498,6 +8499,17 @@ class TestOther : public TestFixture {
84988499
ASSERT_EQUALS("", errout_str());
84998500
}
85008501

8502+
void duplicateExpression23() { // #12282
8503+
// long double literals out of the range of double are different values
8504+
check("long double f() {\n"
8505+
" return 1e400L / 1e500L;\n"
8506+
"}\n"
8507+
"int g(long double x) {\n"
8508+
" return x == 1e400L || x == 1e500L;\n"
8509+
"}\n");
8510+
ASSERT_EQUALS("", errout_str());
8511+
}
8512+
85018513
void duplicateExpression22() {
85028514
check("int f() {\n" // #14913
85038515
" return 0x1 | (0x2 | 0x4) | 0x1;\n"

0 commit comments

Comments
 (0)