Skip to content

Commit be744da

Browse files
author
Balazs Benics
committed
[analyzer] Fix ValistChecker false-positive involving symbolic pointers
In the following example: int va_list_get_int(va_list *va) { return va_arg(*va, int); // FP } The `*va` expression will be something like `Element{SymRegion{va}, 0, va_list}`. We use `ElementRegions` for representing the result of the dereference. In this case, the `IsSymbolic` was set to `false` in the `getVAListAsRegion()`. Hence, before checking if the memregion is a SymRegion, we should take the base of that region. Analogously to the previous example, one can craft other cases: struct MyVaList { va_list l; }; int va_list_get_int(struct MyVaList va) { return va_arg(va.l, int); // FP } But it would also work if the `va_list` would be in the base or derived part of a class. `ObjCIvarRegions` are likely also susceptible. I'm not explicitly demonstrating these cases. PS: Check the `MemRegion::getBaseRegion()` definition. Fixes llvm#55009 Reviewed By: xazax.hun Differential Revision: https://reviews.llvm.org/D124239
1 parent 170a903 commit be744da

File tree

2 files changed

+14
-5
lines changed

2 files changed

+14
-5
lines changed

clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ const MemRegion *ValistChecker::getVAListAsRegion(SVal SV, const Expr *E,
178178
if (isa<ParmVarDecl>(DeclReg->getDecl()))
179179
Reg = C.getState()->getSVal(SV.castAs<Loc>()).getAsRegion();
180180
}
181-
IsSymbolic = Reg && Reg->getAs<SymbolicRegion>();
181+
IsSymbolic = Reg && Reg->getBaseRegion()->getAs<SymbolicRegion>();
182182
// Some VarRegion based VA lists reach here as ElementRegions.
183183
const auto *EReg = dyn_cast_or_null<ElementRegion>(Reg);
184184
return (EReg && VaListModelledAsArray) ? EReg->getSuperRegion() : Reg;

clang/test/Analysis/valist-uninitialized-no-undef.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,20 @@ void call_inlined_uses_arg(int fst, ...) {
1616

1717
void f6(va_list *fst, ...) {
1818
va_start(*fst, fst);
19-
// FIXME: There should be no warning for this.
20-
(void)va_arg(*fst, int); // expected-warning{{va_arg() is called on an uninitialized va_list}}
21-
// expected-note@-1{{va_arg() is called on an uninitialized va_list}}
19+
(void)va_arg(*fst, int);
2220
va_end(*fst);
23-
}
21+
}
22+
23+
int va_list_get_int(va_list *va) {
24+
return va_arg(*va, int); // no-warning
25+
}
26+
27+
struct MyVaList {
28+
va_list l;
29+
};
30+
int va_list_get_int2(struct MyVaList *va) {
31+
return va_arg(va->l, int); // no-warning
32+
}
2433

2534
void call_vprintf_bad(int isstring, ...) {
2635
va_list va;

0 commit comments

Comments
 (0)