[analyzer] Do not report uninitialized value warnings inside swap functions.

This silences warnings that could occur when one is swapping partially initialized structs. We suppress
not only the assignments of uninitialized members, but any values inside swap because swap could
potentially be used as a subroutine to swap class members.

This silences a warning from std::try::function::swap() on partially initialized objects.

llvm-svn: 184256
This commit is contained in:
Anna Zaks 2013-06-18 23:16:15 +00:00
parent 6b08388940
commit 0325646705
3 changed files with 32 additions and 0 deletions

View File

@ -40,6 +40,15 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
ProgramStateRef state = C.getState(); ProgramStateRef state = C.getState();
const LocationContext *LCtx = C.getLocationContext(); const LocationContext *LCtx = C.getLocationContext();
if (state->getSVal(B, LCtx).isUndef()) { if (state->getSVal(B, LCtx).isUndef()) {
// Do not report assignments of uninitialized values inside swap functions.
// This should allow to swap partially uninitialized structs
// (radar://14129997)
if (const FunctionDecl *EnclosingFunctionDecl =
dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
return;
// Generate an error node. // Generate an error node.
ExplodedNode *N = C.generateSink(); ExplodedNode *N = C.generateSink();
if (!N) if (!N)

View File

@ -38,6 +38,14 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
if (!val.isUndef()) if (!val.isUndef())
return; return;
// Do not report assignments of uninitialized values inside swap functions.
// This should allow to swap partially uninitialized structs
// (radar://14129997)
if (const FunctionDecl *EnclosingFunctionDecl =
dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
return;
ExplodedNode *N = C.generateSink(); ExplodedNode *N = C.generateSink();
if (!N) if (!N)

View File

@ -76,3 +76,18 @@ void PR10163 (void) {
test_PR10163(x[1]); // expected-warning{{uninitialized value}} test_PR10163(x[1]); // expected-warning{{uninitialized value}}
} }
struct MyStr {
int x;
int y;
};
void swap(struct MyStr *To, struct MyStr *From) {
// This is not really a swap but close enough for our test.
To->x = From->x;
To->y = From->y; // no warning
}
int test_undefined_member_assignment_in_swap(struct MyStr *s2) {
struct MyStr s1;
s1.x = 5;
swap(s2, &s1);
return s2->y; // expected-warning{{Undefined or garbage value returned to caller}}
}