You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 8502e53
Browse filesBrowse the repository at this point in the historyBrowse files
Fix #15000: Propagate integral cast ranges to condition analysis
Impossible bounds on integral casts must not be propagated through
arithmetic with unsigned result type, because wrap-around invalidates
the bounds. '(uint32_t)x - 1u == 0xFFFFFFFFu' must not be reported as
an always-false condition, since 0u - 1u wraps to 4294967295.
- Filter impossible integral bounds from the operand values before
interval inference in valueFlowInferCondition() when the arithmetic
result type is an unsigned integer (+, -, *).
- Skip impossible-bounded operand pairs in the binary calculation
branch of setTokenValue() under the same result-type predicate.
- Known and possible values, impossible point values, comparisons,
pointer arithmetic and arithmetic with signed result type are
preserved.
Copy file name to clipboardExpand all lines: test/testcondition.cpp
+93Lines changed: 93 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -6612,6 +6612,99 @@ class TestCondition : public TestFixture {
6612
6612
"[test.cpp:4:13]: (style) Comparing expression of type 'const unsigned int &' against value 4294967295. Condition is always false. [compareValueOutOfTypeRangeError]\n",
6613
6613
errout_str());
6614
6614
6615
+
// PR review: no false positive when unsigned arithmetic wraps around
6616
+
check("void f(int x) {\n"
6617
+
" if ((unsigned int)x - 1u == 0xFFFFFFFFu) {}\n"
6618
+
"}\n", settingsUnix64);
6619
+
ASSERT_EQUALS("", errout_str());
6620
+
6621
+
check("void f(int x) {\n"
6622
+
" if ((unsigned short)x - 1u == 0xFFFFFFFFu) {}\n"
6623
+
"}\n", settingsUnix64);
6624
+
ASSERT_EQUALS("", errout_str());
6625
+
6626
+
// Signed result type after integer promotion must still warn
6627
+
check("void f(int x) {\n"
6628
+
" if ((unsigned short)x + 1 == 0) {}\n"
6629
+
"}\n", settingsUnix64);
6630
+
ASSERT_EQUALS("[test.cpp:2:29]: (style) Condition '(unsigned short)x+1==0' is always false [knownConditionTrueFalse]\n",
6631
+
errout_str());
6632
+
6633
+
// Direct cast bounds are preserved
6634
+
check("void f(int x) {\n"
6635
+
" if ((unsigned int)x > 4294967295ULL) {}\n"
6636
+
"}\n", settingsUnix64);
6637
+
ASSERT_EQUALS("[test.cpp:2:25]: (style) Comparing expression of type 'unsigned int' against value 4294967295. Condition is always false. [compareValueOutOfTypeRangeError]\n",
6638
+
errout_str());
6639
+
6640
+
// Reproduce the original typedef-heavy Simulink-generated pattern from #15000.
6641
+
check("void f(unsigned int x) {\n"
6642
+
" unsigned long long tmp = ((unsigned long long)x) + 1ULL;\n"
6643
+
" if (tmp > 4294967295ULL)\n"
6644
+
" tmp = 4294967295ULL;\n"
6645
+
" if ((((long long)((unsigned int)tmp)) - 1LL) < 0LL) {}\n"
6646
+
" if ((((long long)((unsigned int)tmp)) - 1LL) > 4294967295LL) {}\n"
6647
+
"}\n", settingsUnix64);
6648
+
ASSERT_EQUALS("[test.cpp:6:50]: (style) Condition '(((long long)((unsigned int)tmp))-1LL)>4294967295LL' is always false [knownConditionTrueFalse]\n",
6649
+
errout_str());
6650
+
6651
+
check("void f(unsigned long long tmp) {\n"
6652
+
" if (tmp > 4294967295ULL)\n"
6653
+
" tmp = 4294967295ULL;\n"
6654
+
" if (static_cast<long long>(static_cast<unsigned int>(tmp)) - 1LL > 4294967295LL) {}\n"
6655
+
"}\n", settingsUnix64);
6656
+
ASSERT_EQUALS("[test.cpp:4:70]: (style) Condition 'static_cast<long long>(static_cast<unsigned int>(tmp))-1LL>4294967295LL' is always false [knownConditionTrueFalse]\n",
6657
+
errout_str());
6658
+
6659
+
// cast directly around variable: both the range-based and the declared-type
6660
+
// analysis can prove the condition invariant; diag() must prevent duplicates
6661
+
check("void f(unsigned char c) {\n"
6662
+
" if ((unsigned char)c > 255) {}\n"
6663
+
"}\n", settingsUnix64);
6664
+
ASSERT_EQUALS("[test.cpp:2:28]: (style) Comparing expression of type 'unsigned char' against value 255. Condition is always false. [compareValueOutOfTypeRangeError]\n",
6665
+
errout_str());
6666
+
6667
+
check("void f(unsigned char c) {\n"
6668
+
" if ((unsigned char)c == 256) {}\n"
6669
+
"}\n", settingsUnix64);
6670
+
ASSERT_EQUALS("[test.cpp:2:29]: (style) Comparing expression of type 'unsigned char' against value 256. Condition is always false. [compareValueOutOfTypeRangeError]\n",
6671
+
errout_str());
6672
+
6673
+
check("void f(unsigned int u) {\n"
6674
+
" if ((unsigned int)u > 4294967295ULL) {}\n"
6675
+
"}\n", settingsUnix64);
6676
+
ASSERT_EQUALS("[test.cpp:2:27]: (style) Comparing expression of type 'unsigned int' against value 4294967295. Condition is always false. [compareValueOutOfTypeRangeError]\n",
6677
+
errout_str());
6678
+
6679
+
check("void f(unsigned short s) {\n"
6680
+
" if ((unsigned int)s > 4294967295ULL) {}\n"
6681
+
"}\n", settingsUnix64);
6682
+
ASSERT_EQUALS("[test.cpp:2:27]: (style) Comparing expression of type 'unsigned int' against value 4294967295. Condition is always false. [compareValueOutOfTypeRangeError]\n",
6683
+
errout_str());
6684
+
6685
+
// wchar_t range is derived through ValueType::getSizeOf()
6686
+
check("void f(wchar_t c) {\n"
6687
+
" if ((wchar_t)c > 0x7fffffff) {}\n"
6688
+
"}\n", settingsUnix64);
6689
+
ASSERT_EQUALS("[test.cpp:2:20]: (style) Condition '(wchar_t)c>0x7fffffff' is always false [knownConditionTrueFalse]\n",
6690
+
errout_str());
6691
+
6692
+
check("void f(unsigned int x) {\n"
6693
+
" if (-(signed char)x < -129) {}\n"
6694
+
"}\n", settingsUnix64);
6695
+
ASSERT_EQUALS("[test.cpp:2:25]: (style) Condition '-(char)x<-129' is always false [knownConditionTrueFalse]\n",
0 commit comments