Skip to content

Commit bcc3a8d

Browse files
committed
[clang][Analyzer] Fix error path of builtin overflow
1 parent 722d589 commit bcc3a8d

File tree

3 files changed

+35
-38
lines changed

3 files changed

+35
-38
lines changed

clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,9 @@ class BuiltinFunctionChecker : public Checker<eval::Call> {
9696
void handleOverflowBuiltin(const CallEvent &Call, CheckerContext &C,
9797
BinaryOperator::Opcode Op,
9898
QualType ResultType) const;
99-
const NoteTag *createBuiltinNoOverflowNoteTag(CheckerContext &C,
100-
bool BothFeasible, SVal Arg1,
101-
SVal Arg2, SVal Result) const;
102-
const NoteTag *createBuiltinOverflowNoteTag(CheckerContext &C) const;
99+
const NoteTag *createBuiltinOverflowNoteTag(CheckerContext &C,
100+
bool BothFeasible, SVal Arg1,
101+
SVal Arg2, SVal Result) const;
103102
std::pair<bool, bool> checkOverflow(CheckerContext &C, SVal RetVal,
104103
QualType Res) const;
105104

@@ -121,30 +120,25 @@ class BuiltinFunctionChecker : public Checker<eval::Call> {
121120

122121
} // namespace
123122

124-
const NoteTag *BuiltinFunctionChecker::createBuiltinNoOverflowNoteTag(
125-
CheckerContext &C, bool BothFeasible, SVal Arg1, SVal Arg2,
123+
const NoteTag *BuiltinFunctionChecker::createBuiltinOverflowNoteTag(
124+
CheckerContext &C, bool overflow, SVal Arg1, SVal Arg2,
126125
SVal Result) const {
127-
return C.getNoteTag([Result, Arg1, Arg2, BothFeasible](
126+
return C.getNoteTag([Result, Arg1, Arg2, overflow](
128127
PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
129128
if (!BR.isInteresting(Result))
130129
return;
131130

132-
// Propagate interestingness to input argumets if result is interesting.
131+
// Propagate interestingness to input arguments if result is interesting.
133132
BR.markInteresting(Arg1);
134133
BR.markInteresting(Arg2);
135134

136-
if (BothFeasible)
135+
if (overflow)
136+
OS << "Assuming overflow";
137+
else
137138
OS << "Assuming no overflow";
138139
});
139140
}
140141

141-
const NoteTag *
142-
BuiltinFunctionChecker::createBuiltinOverflowNoteTag(CheckerContext &C) const {
143-
return C.getNoteTag([](PathSensitiveBugReport &BR,
144-
llvm::raw_ostream &OS) { OS << "Assuming overflow"; },
145-
/*isPrunable=*/true);
146-
}
147-
148142
std::pair<bool, bool>
149143
BuiltinFunctionChecker::checkOverflow(CheckerContext &C, SVal RetVal,
150144
QualType Res) const {
@@ -194,30 +188,29 @@ void BuiltinFunctionChecker::handleOverflowBuiltin(const CallEvent &Call,
194188
SVal RetVal = SVB.evalBinOp(State, Op, Arg1, Arg2, ResultType);
195189

196190
auto [Overflow, NotOverflow] = checkOverflow(C, RetValMax, ResultType);
197-
if (NotOverflow) {
198-
ProgramStateRef StateNoOverflow = State->BindExpr(
199-
CE, C.getLocationContext(), SVB.makeTruthVal(false, BoolTy));
191+
auto initializeState = [&](bool isOverflow) {
192+
ProgramStateRef NewState = State->BindExpr(
193+
CE, C.getLocationContext(), SVB.makeTruthVal(isOverflow, BoolTy));
200194

201195
if (auto L = Call.getArgSVal(2).getAs<Loc>()) {
202-
StateNoOverflow =
203-
StateNoOverflow->bindLoc(*L, RetVal, C.getLocationContext());
196+
NewState = NewState->bindLoc(*L, RetVal, C.getLocationContext());
204197

205-
// Propagate taint if any of the argumets were tainted
198+
// Propagate taint if any of the arguments were tainted
206199
if (isTainted(State, Arg1) || isTainted(State, Arg2))
207-
StateNoOverflow = addTaint(StateNoOverflow, *L);
200+
NewState = addTaint(NewState, *L);
208201
}
209202

210203
C.addTransition(
211-
StateNoOverflow,
212-
createBuiltinNoOverflowNoteTag(
213-
C, /*BothFeasible=*/NotOverflow && Overflow, Arg1, Arg2, RetVal));
214-
}
204+
NewState,
205+
createBuiltinOverflowNoteTag(
206+
C, /*overflow=*/isOverflow, Arg1, Arg2, RetVal));
207+
};
215208

216-
if (Overflow) {
217-
C.addTransition(State->BindExpr(CE, C.getLocationContext(),
218-
SVB.makeTruthVal(true, BoolTy)),
219-
createBuiltinOverflowNoteTag(C));
220-
}
209+
if (NotOverflow)
210+
initializeState(false);
211+
212+
if (Overflow)
213+
initializeState(true);
221214
}
222215

223216
bool BuiltinFunctionChecker::isBuiltinLikeFunction(

clang/test/Analysis/builtin_overflow.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ void test_add_overflow(void)
2626
int res;
2727

2828
if (__builtin_add_overflow(__INT_MAX__, 1, &res)) {
29-
clang_analyzer_dump_int(res); //expected-warning{{1st function call argument is an uninitialized value}}
29+
clang_analyzer_dump_int(res); //expected-warning{{-2147483648 S32b}}
3030
return;
3131
}
3232

@@ -38,7 +38,7 @@ void test_add_underoverflow(void)
3838
int res;
3939

4040
if (__builtin_add_overflow(__INT_MIN__, -1, &res)) {
41-
clang_analyzer_dump_int(res); //expected-warning{{1st function call argument is an uninitialized value}}
41+
clang_analyzer_dump_int(res); //expected-warning{{2147483647 S32b}}
4242
return;
4343
}
4444

@@ -160,7 +160,7 @@ void test_bool_assign(void)
160160
{
161161
int res;
162162

163-
// Reproduce issue from GH#111147. __builtin_*_overflow funcions
163+
// Reproduce issue from GH#111147. __builtin_*_overflow functions
164164
// should return _Bool, but not int.
165165
_Bool ret = __builtin_mul_overflow(10, 20, &res); // no crash
166166
}

clang/test/Analysis/builtin_overflow_notes.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@ void test_no_overflow_note(int a, int b)
1919

2020
void test_overflow_note(int a, int b)
2121
{
22-
int res; // expected-note{{'res' declared without an initial value}}
22+
int res;
2323

2424
if (__builtin_add_overflow(a, b, &res)) { // expected-note {{Assuming overflow}}
2525
// expected-note@-1 {{Taking true branch}}
26-
int var = res; // expected-warning{{Assigned value is uninitialized}}
27-
// expected-note@-1 {{Assigned value is uninitialized}}
26+
if (res) { // expected-note {{Assuming 'res' is not equal to 0}}
27+
// expected-note@-1 {{Taking true branch}}
28+
int *ptr = 0; // expected-note {{'ptr' initialized to a null pointer value}}
29+
int var = *(int *) ptr; //expected-warning {{Dereference of null pointer}}
30+
//expected-note@-1 {{Dereference of null pointer}}
31+
}
2832
return;
2933
}
3034
}

0 commit comments

Comments
 (0)