Skip to content

Commit 984c577

Browse files
authored
[analyzer] Fix BuiltingFunctionChecker crash on large types (llvm#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 llvm#173795 rdar://166709144
1 parent 191b9cd commit 984c577

File tree

2 files changed

+66
-14
lines changed

2 files changed

+66
-14
lines changed

clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,8 @@ QualType getSufficientTypeForOverflowOp(CheckerContext &C, const QualType &T) {
3636
assert(T->isIntegerType());
3737

3838
ASTContext &ACtx = C.getASTContext();
39-
4039
unsigned BitWidth = ACtx.getIntWidth(T);
41-
return ACtx.getIntTypeForBitwidth(BitWidth * 2, T->isSignedIntegerType());
40+
return ACtx.getBitIntType(T->isUnsignedIntegerType(), BitWidth * 2);
4241
}
4342

4443
QualType getOverflowBuiltinResultType(const CallEvent &Call) {
@@ -208,8 +207,10 @@ void BuiltinFunctionChecker::handleOverflowBuiltin(const CallEvent &Call,
208207
SVal Arg1 = Call.getArgSVal(0);
209208
SVal Arg2 = Call.getArgSVal(1);
210209

211-
SVal RetValMax = SVB.evalBinOp(State, Op, Arg1, Arg2,
212-
getSufficientTypeForOverflowOp(C, ResultType));
210+
QualType SufficientlyWideTy = getSufficientTypeForOverflowOp(C, ResultType);
211+
assert(!SufficientlyWideTy.isNull());
212+
213+
SVal RetValMax = SVB.evalBinOp(State, Op, Arg1, Arg2, SufficientlyWideTy);
213214
SVal RetVal = SVB.evalBinOp(State, Op, Arg1, Arg2, ResultType);
214215

215216
auto [Overflow, NotOverflow] = checkOverflow(C, RetValMax, ResultType);

clang/test/Analysis/builtin_overflow.c

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
// RUN: %clang_analyze_cc1 -triple x86_64-unknown-unknown -verify %s \
1+
// RUN: %clang_analyze_cc1 -triple x86_64-unknown-unknown -verify %s -Wno-strict-prototypes \
22
// RUN: -analyzer-checker=core,debug.ExprInspection,alpha.core.BoolAssignment
33

44
#define __UINT_MAX__ (__INT_MAX__ * 2U + 1U)
55
#define __INT_MIN__ (-__INT_MAX__ - 1)
6+
#define __UINT128_MAX__ ((__uint128_t)((__int128_t)(-1L)))
7+
#define __INT128_MAX__ ((__int128_t)(__UINT128_MAX__ >> 1))
8+
#define __UBITINT_MAX__(BITS) ((unsigned _BitInt(BITS))-1)
9+
#define __BITINT_MAX__(BITS) ((_BitInt(BITS))(__UBITINT_MAX__(BITS) >> 1))
610

7-
void clang_analyzer_dump_int(int);
8-
void clang_analyzer_dump_long(long);
11+
void clang_analyzer_dump(/*not specified*/);
912
void clang_analyzer_eval(int);
1013
void clang_analyzer_warnIfReached(void);
1114

@@ -14,19 +17,19 @@ void test_add_nooverflow(void)
1417
int res;
1518

1619
if (__builtin_add_overflow(10, 20, &res)) {
17-
clang_analyzer_warnIfReached();
20+
clang_analyzer_warnIfReached(); // no-wrapping happened
1821
return;
1922
}
2023

21-
clang_analyzer_dump_int(res); //expected-warning{{30 S32b}}
24+
clang_analyzer_dump(res); //expected-warning{{30 S32b}}
2225
}
2326

2427
void test_add_overflow(void)
2528
{
2629
int res;
2730

2831
if (__builtin_add_overflow(__INT_MAX__, 1, &res)) {
29-
clang_analyzer_dump_int(res); //expected-warning{{-2147483648 S32b}}
32+
clang_analyzer_dump(res); //expected-warning{{-2147483648 S32b}}
3033
return;
3134
}
3235

@@ -38,7 +41,7 @@ void test_add_underoverflow(void)
3841
int res;
3942

4043
if (__builtin_add_overflow(__INT_MIN__, -1, &res)) {
41-
clang_analyzer_dump_int(res); //expected-warning{{2147483647 S32b}}
44+
clang_analyzer_dump(res); //expected-warning{{2147483647 S32b}}
4245
return;
4346
}
4447

@@ -76,7 +79,7 @@ void test_sub_nooverflow(void)
7679
return;
7780
}
7881

79-
clang_analyzer_dump_int(res); //expected-warning{{2147483646 S32b}}
82+
clang_analyzer_dump(res); //expected-warning{{2147483646 S32b}}
8083
}
8184

8285
void test_mul_overflow(void)
@@ -110,7 +113,7 @@ void test_mul_nooverflow(void)
110113
return;
111114
}
112115

113-
clang_analyzer_dump_int(res); //expected-warning{{-20 S32b}}
116+
clang_analyzer_dump(res); //expected-warning{{-20 S32b}}
114117
}
115118

116119
void test_nooverflow_diff_types(void)
@@ -123,7 +126,7 @@ void test_nooverflow_diff_types(void)
123126
return;
124127
}
125128

126-
clang_analyzer_dump_long(res); //expected-warning{{2147483648 S64b}}
129+
clang_analyzer_dump(res); //expected-warning{{2147483648 S64b}}
127130
}
128131

129132
void test_uaddll_overflow_contraints(unsigned long a, unsigned long b)
@@ -164,3 +167,51 @@ void test_bool_assign(void)
164167
// should return _Bool, but not int.
165168
_Bool ret = __builtin_mul_overflow(10, 20, &res); // no crash
166169
}
170+
171+
void no_crash_with_int128(__int128_t a, __int128_t b) {
172+
__int128_t result = 0;
173+
(void)__builtin_add_overflow(a, b, &result); // no-crash
174+
}
175+
176+
void no_crash_with_uint128(__uint128_t a, __uint128_t b) {
177+
__uint128_t result = 0;
178+
(void)__builtin_add_overflow(a, b, &result); // no-crash
179+
}
180+
181+
void no_crash_with_bigint(_BitInt(111) a, _BitInt(111) b) {
182+
_BitInt(111) result = 0;
183+
(void)__builtin_add_overflow(a, b, &result); // no-crash
184+
}
185+
186+
void test_add_overflow_128(void) {
187+
__int128_t res;
188+
189+
if (__builtin_add_overflow(__INT128_MAX__, 1, &res)) {
190+
clang_analyzer_dump(res); // expected-warning {{-170141183460469231731687303715884105728 S128b}}
191+
return;
192+
}
193+
194+
clang_analyzer_warnIfReached(); // no-warning: we always get an overflow, thus choose the other branch
195+
}
196+
197+
void test_add_overflow_u111(void) {
198+
unsigned _BitInt(111) res;
199+
200+
if (__builtin_add_overflow(__UBITINT_MAX__(111), 1, &res)) {
201+
clang_analyzer_dump(res); // expected-warning {{0 U111b}}
202+
return;
203+
}
204+
205+
clang_analyzer_warnIfReached(); // no-warning: we always get an overflow, thus choose the other branch
206+
}
207+
208+
void test_add_overflow_s111(void) {
209+
_BitInt(111) res;
210+
211+
if (__builtin_add_overflow(__BITINT_MAX__(111), 1, &res)) {
212+
clang_analyzer_dump(res); // expected-warning {{-1298074214633706907132624082305024 S111b}}
213+
return;
214+
}
215+
216+
clang_analyzer_warnIfReached(); // no-warning: we always get an overflow, thus choose the other branch
217+
}

0 commit comments

Comments
 (0)