forked from OSchip/llvm-project
[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 #55009 Reviewed By: xazax.hun Differential Revision: https://reviews.llvm.org/D124239
This commit is contained in:
parent
170a903144
commit
be744da01f
clang
|
@ -178,7 +178,7 @@ const MemRegion *ValistChecker::getVAListAsRegion(SVal SV, const Expr *E,
|
|||
if (isa<ParmVarDecl>(DeclReg->getDecl()))
|
||||
Reg = C.getState()->getSVal(SV.castAs<Loc>()).getAsRegion();
|
||||
}
|
||||
IsSymbolic = Reg && Reg->getAs<SymbolicRegion>();
|
||||
IsSymbolic = Reg && Reg->getBaseRegion()->getAs<SymbolicRegion>();
|
||||
// Some VarRegion based VA lists reach here as ElementRegions.
|
||||
const auto *EReg = dyn_cast_or_null<ElementRegion>(Reg);
|
||||
return (EReg && VaListModelledAsArray) ? EReg->getSuperRegion() : Reg;
|
||||
|
|
|
@ -16,11 +16,20 @@ void call_inlined_uses_arg(int fst, ...) {
|
|||
|
||||
void f6(va_list *fst, ...) {
|
||||
va_start(*fst, fst);
|
||||
// FIXME: There should be no warning for this.
|
||||
(void)va_arg(*fst, int); // expected-warning{{va_arg() is called on an uninitialized va_list}}
|
||||
// expected-note@-1{{va_arg() is called on an uninitialized va_list}}
|
||||
(void)va_arg(*fst, int);
|
||||
va_end(*fst);
|
||||
}
|
||||
}
|
||||
|
||||
int va_list_get_int(va_list *va) {
|
||||
return va_arg(*va, int); // no-warning
|
||||
}
|
||||
|
||||
struct MyVaList {
|
||||
va_list l;
|
||||
};
|
||||
int va_list_get_int2(struct MyVaList *va) {
|
||||
return va_arg(va->l, int); // no-warning
|
||||
}
|
||||
|
||||
void call_vprintf_bad(int isstring, ...) {
|
||||
va_list va;
|
||||
|
|
Loading…
Reference in New Issue