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@-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@+2 {{Assuming 't' is >= -446744073709551616}} + // expected-note@+1 {{Taking false branch}} + if (t < 18000000000000000000ULL) + return 0; + return x >> t; // no-crash: gh #218867 + // expected-warning@-1 {{Right shift overflows the capacity of 'unsigned int'}} + // expected-note@-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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
