Skip to content

Commit 925247b

Browse files
committed
[StaticAnalyzer] Fix non decimal macro values in tryExpandAsInteger
Values were parsed into an unsigned APInt with just enough of a bit width to hold the number then interpreted as signed values. This resulted in hex, octal and binary literals from being interpreted as negative when the most significant bit is 1. For example the `-0b11` would have a bit width of 2, would be interpreted as -1, then negated to become 1.
1 parent e47e9f3 commit 925247b

File tree

2 files changed

+26
-4
lines changed

2 files changed

+26
-4
lines changed

clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,19 +142,25 @@ std::optional<int> tryExpandAsInteger(StringRef Macro, const Preprocessor &PP) {
142142
if (InvalidSpelling)
143143
return std::nullopt;
144144

145-
llvm::APInt IntValue;
145+
llvm::APSInt IntValue(0, true);
146146
constexpr unsigned AutoSenseRadix = 0;
147-
if (ValueStr.getAsInteger(AutoSenseRadix, IntValue))
147+
if (ValueStr.getAsInteger(AutoSenseRadix,
148+
static_cast<llvm::APInt &>(IntValue)))
148149
return std::nullopt;
149150

150151
// Parse an optional minus sign.
151152
size_t Size = FilteredTokens.size();
152153
if (Size >= 2) {
153-
if (FilteredTokens[Size - 2].is(tok::minus))
154+
if (FilteredTokens[Size - 2].is(tok::minus)) {
155+
// Make sure there's space for a sign bit
156+
if (IntValue.isSignBitSet())
157+
IntValue = IntValue.extend(IntValue.getBitWidth() + 1);
158+
IntValue.setIsUnsigned(false);
154159
IntValue = -IntValue;
160+
}
155161
}
156162

157-
return IntValue.getSExtValue();
163+
return IntValue.getExtValue();
158164
}
159165

160166
OperatorKind operationKindFromOverloadedOperator(OverloadedOperatorKind OOK,
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %clang_analyze_cc1 -std=c23 -analyzer-checker=core,unix.StdCLibraryFunctions,debug.ExprInspection -verify -analyzer-config eagerly-assume=false %s
2+
3+
void clang_analyzer_eval(int);
4+
5+
typedef struct FILE FILE;
6+
/// Test that the static analyzer doesn't interpret the most significant bit as the sign bit.
7+
// Unorthodox EOF value with a power of 2 radix
8+
#define EOF (-0b11)
9+
10+
int getc(FILE *);
11+
void test_getc(FILE *fp) {
12+
int y = getc(fp);
13+
if (y < 0) {
14+
clang_analyzer_eval(y == EOF); // expected-warning{{TRUE}}
15+
}
16+
}

0 commit comments

Comments
 (0)