Author: Balázs Benics Date: 2026-01-05T11:16:15Z New Revision: 984c57794f9e8253ababfebe84303bda33e8f388
URL: https://github.com/llvm/llvm-project/commit/984c57794f9e8253ababfebe84303bda33e8f388 DIFF: https://github.com/llvm/llvm-project/commit/984c57794f9e8253ababfebe84303bda33e8f388.diff LOG: [analyzer] Fix BuiltingFunctionChecker crash on large types (#174335) Previously, if the result type was 'large' (at least 65 bits), then the ASTContext::getIntTypeForBitwidth would return an empty QualType, causing later a crash when we assume it's non-empty. Instead of using this API, we could piggyback on the BigInt type to formulate a "large enough" type for calculating the mathematically correct result for the operation to check against. Crash: https://godbolt.org/z/dGY3vh39a ```c++ void bigint(_BitInt(63) a, _BitInt(63) b) { _BitInt(63) result = 0; (void)__builtin_add_overflow(a, b, &result); // crashes here } ``` Fixes #173795 rdar://166709144 Added: Modified: clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp clang/test/Analysis/builtin_overflow.c Removed: ################################################################################ diff --git a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp index 8eb68b1fa638e..f50a3b08671e2 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp @@ -36,9 +36,8 @@ QualType getSufficientTypeForOverflowOp(CheckerContext &C, const QualType &T) { assert(T->isIntegerType()); ASTContext &ACtx = C.getASTContext(); - unsigned BitWidth = ACtx.getIntWidth(T); - return ACtx.getIntTypeForBitwidth(BitWidth * 2, T->isSignedIntegerType()); + return ACtx.getBitIntType(T->isUnsignedIntegerType(), BitWidth * 2); } QualType getOverflowBuiltinResultType(const CallEvent &Call) { @@ -208,8 +207,10 @@ void BuiltinFunctionChecker::handleOverflowBuiltin(const CallEvent &Call, SVal Arg1 = Call.getArgSVal(0); SVal Arg2 = Call.getArgSVal(1); - SVal RetValMax = SVB.evalBinOp(State, Op, Arg1, Arg2, - getSufficientTypeForOverflowOp(C, ResultType)); + QualType SufficientlyWideTy = getSufficientTypeForOverflowOp(C, ResultType); + assert(!SufficientlyWideTy.isNull()); + + SVal RetValMax = SVB.evalBinOp(State, Op, Arg1, Arg2, SufficientlyWideTy); SVal RetVal = SVB.evalBinOp(State, Op, Arg1, Arg2, ResultType); auto [Overflow, NotOverflow] = checkOverflow(C, RetValMax, ResultType); diff --git a/clang/test/Analysis/builtin_overflow.c b/clang/test/Analysis/builtin_overflow.c index d290333071dc9..ba7e52703fefe 100644 --- a/clang/test/Analysis/builtin_overflow.c +++ b/clang/test/Analysis/builtin_overflow.c @@ -1,11 +1,14 @@ -// RUN: %clang_analyze_cc1 -triple x86_64-unknown-unknown -verify %s \ +// RUN: %clang_analyze_cc1 -triple x86_64-unknown-unknown -verify %s -Wno-strict-prototypes \ // RUN: -analyzer-checker=core,debug.ExprInspection,alpha.core.BoolAssignment #define __UINT_MAX__ (__INT_MAX__ * 2U + 1U) #define __INT_MIN__ (-__INT_MAX__ - 1) +#define __UINT128_MAX__ ((__uint128_t)((__int128_t)(-1L))) +#define __INT128_MAX__ ((__int128_t)(__UINT128_MAX__ >> 1)) +#define __UBITINT_MAX__(BITS) ((unsigned _BitInt(BITS))-1) +#define __BITINT_MAX__(BITS) ((_BitInt(BITS))(__UBITINT_MAX__(BITS) >> 1)) -void clang_analyzer_dump_int(int); -void clang_analyzer_dump_long(long); +void clang_analyzer_dump(/*not specified*/); void clang_analyzer_eval(int); void clang_analyzer_warnIfReached(void); @@ -14,11 +17,11 @@ void test_add_nooverflow(void) int res; if (__builtin_add_overflow(10, 20, &res)) { - clang_analyzer_warnIfReached(); + clang_analyzer_warnIfReached(); // no-wrapping happened return; } - clang_analyzer_dump_int(res); //expected-warning{{30 S32b}} + clang_analyzer_dump(res); //expected-warning{{30 S32b}} } void test_add_overflow(void) @@ -26,7 +29,7 @@ void test_add_overflow(void) int res; if (__builtin_add_overflow(__INT_MAX__, 1, &res)) { - clang_analyzer_dump_int(res); //expected-warning{{-2147483648 S32b}} + clang_analyzer_dump(res); //expected-warning{{-2147483648 S32b}} return; } @@ -38,7 +41,7 @@ void test_add_underoverflow(void) int res; if (__builtin_add_overflow(__INT_MIN__, -1, &res)) { - clang_analyzer_dump_int(res); //expected-warning{{2147483647 S32b}} + clang_analyzer_dump(res); //expected-warning{{2147483647 S32b}} return; } @@ -76,7 +79,7 @@ void test_sub_nooverflow(void) return; } - clang_analyzer_dump_int(res); //expected-warning{{2147483646 S32b}} + clang_analyzer_dump(res); //expected-warning{{2147483646 S32b}} } void test_mul_overflow(void) @@ -110,7 +113,7 @@ void test_mul_nooverflow(void) return; } - clang_analyzer_dump_int(res); //expected-warning{{-20 S32b}} + clang_analyzer_dump(res); //expected-warning{{-20 S32b}} } void test_nooverflow_ diff _types(void) @@ -123,7 +126,7 @@ void test_nooverflow_ diff _types(void) return; } - clang_analyzer_dump_long(res); //expected-warning{{2147483648 S64b}} + clang_analyzer_dump(res); //expected-warning{{2147483648 S64b}} } void test_uaddll_overflow_contraints(unsigned long a, unsigned long b) @@ -164,3 +167,51 @@ void test_bool_assign(void) // should return _Bool, but not int. _Bool ret = __builtin_mul_overflow(10, 20, &res); // no crash } + +void no_crash_with_int128(__int128_t a, __int128_t b) { + __int128_t result = 0; + (void)__builtin_add_overflow(a, b, &result); // no-crash +} + +void no_crash_with_uint128(__uint128_t a, __uint128_t b) { + __uint128_t result = 0; + (void)__builtin_add_overflow(a, b, &result); // no-crash +} + +void no_crash_with_bigint(_BitInt(111) a, _BitInt(111) b) { + _BitInt(111) result = 0; + (void)__builtin_add_overflow(a, b, &result); // no-crash +} + +void test_add_overflow_128(void) { + __int128_t res; + + if (__builtin_add_overflow(__INT128_MAX__, 1, &res)) { + clang_analyzer_dump(res); // expected-warning {{-170141183460469231731687303715884105728 S128b}} + return; + } + + clang_analyzer_warnIfReached(); // no-warning: we always get an overflow, thus choose the other branch +} + +void test_add_overflow_u111(void) { + unsigned _BitInt(111) res; + + if (__builtin_add_overflow(__UBITINT_MAX__(111), 1, &res)) { + clang_analyzer_dump(res); // expected-warning {{0 U111b}} + return; + } + + clang_analyzer_warnIfReached(); // no-warning: we always get an overflow, thus choose the other branch +} + +void test_add_overflow_s111(void) { + _BitInt(111) res; + + if (__builtin_add_overflow(__BITINT_MAX__(111), 1, &res)) { + clang_analyzer_dump(res); // expected-warning {{-1298074214633706907132624082305024 S111b}} + return; + } + + clang_analyzer_warnIfReached(); // no-warning: we always get an overflow, thus choose the other branch +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
