From d566c345265421dedfb19d0c5a9a431d95b49b14 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Thu, 29 Dec 2016 20:03:55 +0000 Subject: [PATCH] Fix PR31489 - std::function self-swap segfaults llvm-svn: 290721 --- libcxx/include/__functional_03 | 8 + libcxx/include/functional | 2 + .../func.wrap.func.con/copy_assign.pass.cpp | 114 +++++++----- .../func.wrap.func.mod/swap.pass.cpp | 175 +++++++++++++----- 4 files changed, 205 insertions(+), 94 deletions(-) diff --git a/libcxx/include/__functional_03 b/libcxx/include/__functional_03 index f8b5d9566053..a1cec8bcac95 100644 --- a/libcxx/include/__functional_03 +++ b/libcxx/include/__functional_03 @@ -642,6 +642,8 @@ template void function<_Rp()>::swap(function& __f) { + if (_VSTD::addressof(__f) == this) + return; if (__f_ == (__base*)&__buf_ && __f.__f_ == (__base*)&__f.__buf_) { typename aligned_storage::type __tempbuf; @@ -916,6 +918,8 @@ template void function<_Rp(_A0)>::swap(function& __f) { + if (_VSTD::addressof(__f) == this) + return; if (__f_ == (__base*)&__buf_ && __f.__f_ == (__base*)&__f.__buf_) { typename aligned_storage::type __tempbuf; @@ -1190,6 +1194,8 @@ template void function<_Rp(_A0, _A1)>::swap(function& __f) { + if (_VSTD::addressof(__f) == this) + return; if (__f_ == (__base*)&__buf_ && __f.__f_ == (__base*)&__f.__buf_) { typename aligned_storage::type __tempbuf; @@ -1464,6 +1470,8 @@ template void function<_Rp(_A0, _A1, _A2)>::swap(function& __f) { + if (_VSTD::addressof(__f) == this) + return; if (__f_ == (__base*)&__buf_ && __f.__f_ == (__base*)&__f.__buf_) { typename aligned_storage::type __tempbuf; diff --git a/libcxx/include/functional b/libcxx/include/functional index 0c450f15d1e3..eb8609f1469b 100644 --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -1870,6 +1870,8 @@ template void function<_Rp(_ArgTypes...)>::swap(function& __f) _NOEXCEPT { + if (_VSTD::addressof(__f) == this) + return; if ((void *)__f_ == &__buf_ && (void *)__f.__f_ == &__f.__buf_) { typename aligned_storage::type __tempbuf; diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_assign.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_assign.pass.cpp index 6388cddfc6c6..9b83ddecb974 100644 --- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_assign.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_assign.pass.cpp @@ -19,92 +19,120 @@ #include "test_macros.h" #include "count_new.hpp" -class A -{ - int data_[10]; +class A { + int data_[10]; + public: - static int count; + static int count; - A() - { - ++count; - for (int i = 0; i < 10; ++i) - data_[i] = i; - } + A() { + ++count; + for (int i = 0; i < 10; ++i) + data_[i] = i; + } - A(const A&) {++count;} + A(const A &) { ++count; } - ~A() {--count;} + ~A() { --count; } - int operator()(int i) const - { - for (int j = 0; j < 10; ++j) - i += data_[j]; - return i; - } + int operator()(int i) const { + for (int j = 0; j < 10; ++j) + i += data_[j]; + return i; + } }; int A::count = 0; -int g(int) {return 0;} +int g0() { return 0; } +int g(int) { return 0; } +int g2(int, int) { return 2; } +int g3(int, int, int) { return 3; } -int main() -{ - assert(globalMemCounter.checkOutstandingNewEq(0)); - { +int main() { + assert(globalMemCounter.checkOutstandingNewEq(0)); + { std::function f = A(); assert(A::count == 1); assert(globalMemCounter.checkOutstandingNewEq(1)); assert(f.target()); - assert(f.target() == 0); + assert(f.target() == 0); std::function f2; f2 = f; assert(A::count == 2); assert(globalMemCounter.checkOutstandingNewEq(2)); assert(f2.target()); - assert(f2.target() == 0); - } - assert(A::count == 0); - assert(globalMemCounter.checkOutstandingNewEq(0)); - { + assert(f2.target() == 0); + } + assert(A::count == 0); + assert(globalMemCounter.checkOutstandingNewEq(0)); + { std::function f = g; assert(globalMemCounter.checkOutstandingNewEq(0)); - assert(f.target()); + assert(f.target()); assert(f.target() == 0); std::function f2; f2 = f; assert(globalMemCounter.checkOutstandingNewEq(0)); - assert(f2.target()); + assert(f2.target()); assert(f2.target() == 0); - } - assert(globalMemCounter.checkOutstandingNewEq(0)); - { + } + assert(globalMemCounter.checkOutstandingNewEq(0)); + { std::function f; assert(globalMemCounter.checkOutstandingNewEq(0)); - assert(f.target() == 0); + assert(f.target() == 0); assert(f.target() == 0); std::function f2; f2 = f; assert(globalMemCounter.checkOutstandingNewEq(0)); - assert(f2.target() == 0); + assert(f2.target() == 0); assert(f2.target() == 0); - } + } + { + typedef std::function Func; + Func f = g0; + Func& fr = (f = f); + assert(&fr == &f); + assert(*f.target() == g0); + } + { + typedef std::function Func; + Func f = g; + Func& fr = (f = f); + assert(&fr == &f); + assert(*f.target() == g); + } + { + typedef std::function Func; + Func f = g2; + Func& fr = (f = f); + assert(&fr == &f); + assert(*f.target() == g2); + } + { + typedef std::function Func; + Func f = g3; + Func& fr = (f = f); + assert(&fr == &f); + assert(*f.target() == g3); + } #if TEST_STD_VER >= 11 - assert(globalMemCounter.checkOutstandingNewEq(0)); - { + assert(globalMemCounter.checkOutstandingNewEq(0)); + { std::function f = A(); assert(A::count == 1); assert(globalMemCounter.checkOutstandingNewEq(1)); assert(f.target()); - assert(f.target() == 0); + assert(f.target() == 0); std::function f2; f2 = std::move(f); assert(A::count == 1); assert(globalMemCounter.checkOutstandingNewEq(1)); assert(f2.target()); - assert(f2.target() == 0); + assert(f2.target() == 0); assert(f.target() == 0); - assert(f.target() == 0); - } + assert(f.target() == 0); + } #endif } diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.mod/swap.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.mod/swap.pass.cpp index f94e689b2a6b..214c3f7c5d83 100644 --- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.mod/swap.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.mod/swap.pass.cpp @@ -18,46 +18,49 @@ #include "count_new.hpp" -class A -{ - int data_[10]; +class A { + int data_[10]; + public: - static int count; + static int count; - explicit A(int j) - { - ++count; - data_[0] = j; - } + explicit A(int j) { + ++count; + data_[0] = j; + } - A(const A& a) - { - ++count; - for (int i = 0; i < 10; ++i) - data_[i] = a.data_[i]; - } + A(const A &a) { + ++count; + for (int i = 0; i < 10; ++i) + data_[i] = a.data_[i]; + } - ~A() {--count;} + ~A() { --count; } - int operator()(int i) const - { - for (int j = 0; j < 10; ++j) - i += data_[j]; - return i; - } + int operator()(int i) const { + for (int j = 0; j < 10; ++j) + i += data_[j]; + return i; + } - int id() const {return data_[0];} + int operator()() const { return -1; } + int operator()(int, int) const { return -2; } + int operator()(int, int, int) const { return -3; } + + int id() const { return data_[0]; } }; int A::count = 0; -int g(int) {return 0;} -int h(int) {return 1;} +int g0() { return 0; } +int g(int) { return 0; } +int h(int) { return 1; } +int g2(int, int) { return 2; } +int g3(int, int, int) { return 3; } -int main() -{ - assert(globalMemCounter.checkOutstandingNewEq(0)); - { +int main() { + assert(globalMemCounter.checkOutstandingNewEq(0)); + { std::function f1 = A(1); std::function f2 = A(2); assert(A::count == 2); @@ -69,52 +72,122 @@ int main() assert(globalMemCounter.checkOutstandingNewEq(2)); assert(f1.target()->id() == 2); assert(f2.target()->id() == 1); - } - assert(A::count == 0); - assert(globalMemCounter.checkOutstandingNewEq(0)); - { + } + assert(A::count == 0); + assert(globalMemCounter.checkOutstandingNewEq(0)); + { std::function f1 = A(1); std::function f2 = g; assert(A::count == 1); assert(globalMemCounter.checkOutstandingNewEq(1)); assert(f1.target()->id() == 1); - assert(*f2.target() == g); + assert(*f2.target() == g); f1.swap(f2); assert(A::count == 1); assert(globalMemCounter.checkOutstandingNewEq(1)); - assert(*f1.target() == g); + assert(*f1.target() == g); assert(f2.target()->id() == 1); - } - assert(A::count == 0); - assert(globalMemCounter.checkOutstandingNewEq(0)); - { + } + assert(A::count == 0); + assert(globalMemCounter.checkOutstandingNewEq(0)); + { std::function f1 = g; std::function f2 = A(1); assert(A::count == 1); assert(globalMemCounter.checkOutstandingNewEq(1)); - assert(*f1.target() == g); + assert(*f1.target() == g); assert(f2.target()->id() == 1); f1.swap(f2); assert(A::count == 1); assert(globalMemCounter.checkOutstandingNewEq(1)); assert(f1.target()->id() == 1); - assert(*f2.target() == g); - } - assert(A::count == 0); - assert(globalMemCounter.checkOutstandingNewEq(0)); - { + assert(*f2.target() == g); + } + assert(A::count == 0); + assert(globalMemCounter.checkOutstandingNewEq(0)); + { std::function f1 = g; std::function f2 = h; assert(A::count == 0); assert(globalMemCounter.checkOutstandingNewEq(0)); - assert(*f1.target() == g); - assert(*f2.target() == h); + assert(*f1.target() == g); + assert(*f2.target() == h); f1.swap(f2); assert(A::count == 0); assert(globalMemCounter.checkOutstandingNewEq(0)); - assert(*f1.target() == h); - assert(*f2.target() == g); + assert(*f1.target() == h); + assert(*f2.target() == g); + } + assert(A::count == 0); + assert(globalMemCounter.checkOutstandingNewEq(0)); + { + std::function f1 = A(1); + assert(A::count == 1); + { + DisableAllocationGuard guard; + ((void)guard); + f1.swap(f1); } - assert(A::count == 0); - assert(globalMemCounter.checkOutstandingNewEq(0)); + assert(A::count == 1); + assert(f1.target()->id() == 1); + } + assert(A::count == 0); + assert(globalMemCounter.checkOutstandingNewEq(0)); + { + std::function f1 = g0; + DisableAllocationGuard guard; + ((void)guard); + f1.swap(f1); + assert(*f1.target() == g0); + } + assert(globalMemCounter.checkOutstandingNewEq(0)); + { + std::function f1 = g2; + DisableAllocationGuard guard; + ((void)guard); + f1.swap(f1); + assert(*f1.target() == g2); + } + assert(globalMemCounter.checkOutstandingNewEq(0)); + { + std::function f1 = g3; + DisableAllocationGuard guard; + ((void)guard); + f1.swap(f1); + assert(*f1.target() == g3); + } + assert(globalMemCounter.checkOutstandingNewEq(0)); + { + std::function f1 = A(1); + assert(A::count == 1); + DisableAllocationGuard guard; + ((void)guard); + f1.swap(f1); + assert(A::count == 1); + assert(f1.target()->id() == 1); + } + assert(globalMemCounter.checkOutstandingNewEq(0)); + assert(A::count == 0); + { + std::function f1 = A(2); + assert(A::count == 1); + DisableAllocationGuard guard; + ((void)guard); + f1.swap(f1); + assert(A::count == 1); + assert(f1.target()->id() == 2); + } + assert(globalMemCounter.checkOutstandingNewEq(0)); + assert(A::count == 0); + { + std::function f1 = A(3); + assert(A::count == 1); + DisableAllocationGuard guard; + ((void)guard); + f1.swap(f1); + assert(A::count == 1); + assert(f1.target()->id() == 3); + } + assert(globalMemCounter.checkOutstandingNewEq(0)); + assert(A::count == 0); }