[clang] 959e8e7 - [analyzer] Fix assertion in BitwiseShiftChecker from getExtValue (#218940)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 27 00:32:22 PDT 2026
Author: Balázs Benics
Date: 2026-08-27T08:32:17+01:00
New Revision: 959e8e7c74a341dadca6ec7106cc2eae11a5f692
URL: https://github.com/llvm/llvm-project/commit/959e8e7c74a341dadca6ec7106cc2eae11a5f692
DIFF: https://github.com/llvm/llvm-project/commit/959e8e7c74a341dadca6ec7106cc2eae11a5f692.diff
LOG: [analyzer] Fix assertion in BitwiseShiftChecker from getExtValue (#218940)
`APSInt::getExtValue()` asserts `isRepresentableByInt64()`, which for an
unsigned value means it must fit in 63 bits. `checkOvershift()` called
it unguarded on a solver-derived lower bound, so any bound at or above
2^63 crashed with:
`Assertion 'isRepresentableByInt64() && "Too many bits for int64_t"'
failed.`
```c++
unsigned huge_right_operand_symbolic(unsigned x, unsigned long long t) {
if (t < 18000000000000000000ULL)
return 0;
return x >> t; // no-crash: gh #218867
}
```
Format the `APSInt` directly instead. Its stream operator honors the
value's own signedness, so bounds of any width print correctly, matching
how this file already renders `ConcreteInt` operands.
Note that no `_BitInt` is needed to reach this: a plain `unsigned long
long` suffices, as above. On no-assert builds the bug was silent
corruption rather than a crash, emitting a wrapped negative lower bound
for an unsigned value.
The assertion failure was surfaced by #209048 (in clang-23), which
taught the solver to propagate operand ranges through {+,-,*} and so
made these tight, large bounds reachable. But the defect is older:
#74141 introduced the bad call in clang-18.
The new test also pins a pre-existing, unrelated bug: the `Assuming`
path note routes the literal through `APInt`'s stream operator, which
always formats as signed, so `18000000000000000000` prints as a bogus
negative. That one is in `ConditionBRVisitor::patternMatch` and is
display-only -- the value never feeds the analysis. Printing it unsigned
regresses `Analysis/diagnostics/macros.cpp`, where an `int` compared
against `UINT32_MAX` should read `-1`, so the correct signedness depends
on the comparison's converted type rather than the literal's. Left as a
FIXME.
Fixes #218867
Assisted-By: claude
Added:
Modified:
clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp
clang/test/Analysis/bitwise-shift-common.c
Removed:
################################################################################
diff --git a/clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp
index fefd4dca1a08e..3e380fbaae528 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp
@@ -177,7 +177,7 @@ BugReportPtr BitwiseShiftValidator::checkOvershift() {
SValBuilder &SVB = Ctx.getSValBuilder();
if (const llvm::APSInt *MinRight = SVB.getMinValue(FoldedState, Right);
MinRight && *MinRight >= LHSBitWidth) {
- LowerBoundStr = formatv(" >= {0},", MinRight->getExtValue());
+ LowerBoundStr = formatv(" >= {0},", *MinRight);
}
}
diff --git a/clang/test/Analysis/bitwise-shift-common.c b/clang/test/Analysis/bitwise-shift-common.c
index c5a9f4bcdde3c..de83f71ec068b 100644
--- a/clang/test/Analysis/bitwise-shift-common.c
+++ b/clang/test/Analysis/bitwise-shift-common.c
@@ -90,6 +90,19 @@ int too_large_right_operand_symbolic(int left, int right) {
// expected-note at -2 {{The result of right shift is undefined because the right operand is >= 32, not smaller than 32, the capacity of 'int'}}
}
+unsigned huge_right_operand_symbolic(unsigned x, unsigned long long t) {
+ // FIXME: the 'Assuming' note below prints the literal via APInt's stream
+ // operator, which always formats as signed, so 18000000000000000000 comes
+ // out as a bogus negative. That is a bug in ConditionBRVisitor.
+ // expected-note at +2 {{Assuming 't' is >= -446744073709551616}}
+ // expected-note at +1 {{Taking false branch}}
+ if (t < 18000000000000000000ULL)
+ return 0;
+ return x >> t; // no-crash: gh #218867
+ // expected-warning at -1 {{Right shift overflows the capacity of 'unsigned int'}}
+ // expected-note at -2 {{The result of right shift is undefined because the right operand is >= 18000000000000000000, not smaller than 32, the capacity of 'unsigned int'}}
+}
+
void clang_analyzer_value(int);
int too_large_right_operand_compound(unsigned short arg) {
// Note: this would be valid code with an 'unsigned int' because
More information about the cfe-commits
mailing list