From 52810c51afaa10b30319d236d353d70534cf9356 Mon Sep 17 00:00:00 2001 From: Anna Zaks Date: Tue, 18 Jun 2013 23:16:15 +0000 Subject: [PATCH] [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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184256 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Checkers/UndefResultChecker.cpp | 9 +++++++++ .../Checkers/UndefinedAssignmentChecker.cpp | 8 ++++++++ test/Analysis/uninit-vals-ps-region.m | 15 +++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp index 6733563198..3f6549de56 100644 --- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp @@ -40,6 +40,15 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B, ProgramStateRef state = C.getState(); const LocationContext *LCtx = C.getLocationContext(); 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(C.getStackFrame()->getDecl())) + if (C.getCalleeName(EnclosingFunctionDecl) == "swap") + return; + // Generate an error node. ExplodedNode *N = C.generateSink(); if (!N) diff --git a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp index e04f49c374..016e3c8045 100644 --- a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp @@ -38,6 +38,14 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val, if (!val.isUndef()) 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(C.getStackFrame()->getDecl())) + if (C.getCalleeName(EnclosingFunctionDecl) == "swap") + return; + ExplodedNode *N = C.generateSink(); if (!N) diff --git a/test/Analysis/uninit-vals-ps-region.m b/test/Analysis/uninit-vals-ps-region.m index 614ce2fc33..a4aa5a114a 100644 --- a/test/Analysis/uninit-vals-ps-region.m +++ b/test/Analysis/uninit-vals-ps-region.m @@ -76,3 +76,18 @@ void PR10163 (void) { 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}} +} -- 2.40.0