mirror of https://github.com/microsoft/clang.git
[analyzer] Fix autodetection of binding types.
In ProgramState::getSVal(Location, Type) API which dereferences a pointer value, when the optional Type parameter is not supplied and the Location is not typed, type should have been guessed on a best-effort basis by inspecting the Location more deeply. However, this never worked; the auto-detected type was instead a pointer type to the correct type. Fixed the issue and added various test cases to demonstrate which parts of the analyzer were affected (uninitialized pointer argument checker, C++ trivial copy modeling, Google test API modeling checker). Additionally, autodetected void types are automatically replaced with char, in order to simplify checker APIs. Which means that if the location is a void pointer, getSVal() would read the first byte through this pointer and return its symbolic value. Fixes pr34305. Differential Revision: https://reviews.llvm.org/D38358 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@314910 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
c64cb39314
commit
c99811f061
|
@ -1393,16 +1393,19 @@ SVal RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T)
|
||||||
return UnknownVal();
|
return UnknownVal();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isa<AllocaRegion>(MR) ||
|
if (!isa<TypedValueRegion>(MR)) {
|
||||||
isa<SymbolicRegion>(MR) ||
|
|
||||||
isa<CodeTextRegion>(MR)) {
|
|
||||||
if (T.isNull()) {
|
if (T.isNull()) {
|
||||||
if (const TypedRegion *TR = dyn_cast<TypedRegion>(MR))
|
if (const TypedRegion *TR = dyn_cast<TypedRegion>(MR))
|
||||||
T = TR->getLocationType();
|
T = TR->getLocationType()->getPointeeType();
|
||||||
else {
|
else if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
|
||||||
const SymbolicRegion *SR = cast<SymbolicRegion>(MR);
|
T = SR->getSymbol()->getType()->getPointeeType();
|
||||||
T = SR->getSymbol()->getType();
|
else if (isa<AllocaRegion>(MR))
|
||||||
}
|
T = Ctx.VoidTy;
|
||||||
|
}
|
||||||
|
assert(!T.isNull() && "Unable to auto-detect binding type!");
|
||||||
|
if (T->isVoidType()) {
|
||||||
|
// When trying to dereference a void pointer, read the first byte.
|
||||||
|
T = Ctx.CharTy;
|
||||||
}
|
}
|
||||||
MR = GetElementZeroRegion(cast<SubRegion>(MR), T);
|
MR = GetElementZeroRegion(cast<SubRegion>(MR), T);
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,7 +199,7 @@ namespace PODUninitialized {
|
||||||
Inner p;
|
Inner p;
|
||||||
};
|
};
|
||||||
|
|
||||||
void testPOD() {
|
void testPOD(const POD &pp) {
|
||||||
POD p;
|
POD p;
|
||||||
p.x = 1;
|
p.x = 1;
|
||||||
POD p2 = p; // no-warning
|
POD p2 = p; // no-warning
|
||||||
|
@ -210,6 +210,15 @@ namespace PODUninitialized {
|
||||||
// Use rvalues as well.
|
// Use rvalues as well.
|
||||||
clang_analyzer_eval(POD(p3).x == 1); // expected-warning{{TRUE}}
|
clang_analyzer_eval(POD(p3).x == 1); // expected-warning{{TRUE}}
|
||||||
|
|
||||||
|
// Copy from symbolic references correctly.
|
||||||
|
POD p4 = pp;
|
||||||
|
// Make sure that p4.x contains a symbol after copy.
|
||||||
|
if (p4.x > 0)
|
||||||
|
clang_analyzer_eval(p4.x > 0); // expected-warning{{TRUE}}
|
||||||
|
// FIXME: Element region gets in the way, so these aren't the same symbols
|
||||||
|
// as they should be.
|
||||||
|
clang_analyzer_eval(pp.x == p4.x); // expected-warning{{UNKNOWN}}
|
||||||
|
|
||||||
PODWrapper w;
|
PODWrapper w;
|
||||||
w.p.y = 1;
|
w.p.y = 1;
|
||||||
PODWrapper w2 = w; // no-warning
|
PODWrapper w2 = w; // no-warning
|
||||||
|
|
|
@ -21,3 +21,11 @@ static void f2(void *buf) {
|
||||||
memcpy((&x[1]), (buf), 1); // expected-warning{{implicitly declaring library function 'memcpy' with type 'void *(void *, const void *}} \
|
memcpy((&x[1]), (buf), 1); // expected-warning{{implicitly declaring library function 'memcpy' with type 'void *(void *, const void *}} \
|
||||||
// expected-note{{include the header <string.h> or explicitly provide a declaration for 'memcpy'}}
|
// expected-note{{include the header <string.h> or explicitly provide a declaration for 'memcpy'}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AllocaRegion is untyped. Void pointer isn't of much help either. Before
|
||||||
|
// realizing that the value is undefined, we need to somehow figure out
|
||||||
|
// what type of value do we expect.
|
||||||
|
void f3(void *dest) {
|
||||||
|
void *src = __builtin_alloca(5);
|
||||||
|
memcpy(dest, src, 1); // expected-warning{{2nd function call argument is a pointer to uninitialized value}}
|
||||||
|
}
|
||||||
|
|
|
@ -151,3 +151,17 @@ void testConstrainState(int p) {
|
||||||
ASSERT_TRUE(false);
|
ASSERT_TRUE(false);
|
||||||
clang_analyzer_warnIfReached(); // no-warning
|
clang_analyzer_warnIfReached(); // no-warning
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testAssertSymbolicPtr(const bool *b) {
|
||||||
|
ASSERT_TRUE(*b); // no-crash
|
||||||
|
|
||||||
|
// FIXME: Our solver doesn't handle this well yet.
|
||||||
|
clang_analyzer_eval(*b); // expected-warning{{UNKNOWN}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testAssertSymbolicRef(const bool &b) {
|
||||||
|
ASSERT_TRUE(b); // no-crash
|
||||||
|
|
||||||
|
// FIXME: Our solver doesn't handle this well yet.
|
||||||
|
clang_analyzer_eval(b); // expected-warning{{UNKNOWN}}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue