[libcxx] r290721 - Fix PR31489 - std::function self-swap segfaults

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 29 12:03:55 PST 2016


Author: ericwf
Date: Thu Dec 29 14:03:55 2016
New Revision: 290721

URL: http://llvm.org/viewvc/llvm-project?rev=290721&view=rev
Log:
Fix PR31489 - std::function self-swap segfaults

Modified:
    libcxx/trunk/include/__functional_03
    libcxx/trunk/include/functional
    libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_assign.pass.cpp
    libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.mod/swap.pass.cpp

Modified: libcxx/trunk/include/__functional_03
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__functional_03?rev=290721&r1=290720&r2=290721&view=diff
==============================================================================
--- libcxx/trunk/include/__functional_03 (original)
+++ libcxx/trunk/include/__functional_03 Thu Dec 29 14:03:55 2016
@@ -642,6 +642,8 @@ template<class _Rp>
 void
 function<_Rp()>::swap(function& __f)
 {
+    if (_VSTD::addressof(__f) == this)
+      return;
     if (__f_ == (__base*)&__buf_ && __f.__f_ == (__base*)&__f.__buf_)
     {
         typename aligned_storage<sizeof(__buf_)>::type __tempbuf;
@@ -916,6 +918,8 @@ template<class _Rp, class _A0>
 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<sizeof(__buf_)>::type __tempbuf;
@@ -1190,6 +1194,8 @@ template<class _Rp, class _A0, class _A1
 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<sizeof(__buf_)>::type __tempbuf;
@@ -1464,6 +1470,8 @@ template<class _Rp, class _A0, class _A1
 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<sizeof(__buf_)>::type __tempbuf;

Modified: libcxx/trunk/include/functional
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/functional?rev=290721&r1=290720&r2=290721&view=diff
==============================================================================
--- libcxx/trunk/include/functional (original)
+++ libcxx/trunk/include/functional Thu Dec 29 14:03:55 2016
@@ -1870,6 +1870,8 @@ template<class _Rp, class ..._ArgTypes>
 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<sizeof(__buf_)>::type __tempbuf;

Modified: libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_assign.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_assign.pass.cpp?rev=290721&r1=290720&r2=290721&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_assign.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_assign.pass.cpp Thu Dec 29 14:03:55 2016
@@ -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(const A&) {++count;}
-
-    ~A() {--count;}
-
-    int operator()(int i) const
-    {
-        for (int j = 0; j < 10; ++j)
-            i += data_[j];
-        return i;
-    }
+  A() {
+    ++count;
+    for (int i = 0; i < 10; ++i)
+      data_[i] = i;
+  }
+
+  A(const A &) { ++count; }
+
+  ~A() { --count; }
+
+  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 main()
-{
-    assert(globalMemCounter.checkOutstandingNewEq(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));
+  {
     std::function<int(int)> f = A();
     assert(A::count == 1);
     assert(globalMemCounter.checkOutstandingNewEq(1));
     assert(f.target<A>());
-    assert(f.target<int(*)(int)>() == 0);
+    assert(f.target<int (*)(int)>() == 0);
     std::function<int(int)> f2;
     f2 = f;
     assert(A::count == 2);
     assert(globalMemCounter.checkOutstandingNewEq(2));
     assert(f2.target<A>());
-    assert(f2.target<int(*)(int)>() == 0);
-    }
-    assert(A::count == 0);
-    assert(globalMemCounter.checkOutstandingNewEq(0));
-    {
+    assert(f2.target<int (*)(int)>() == 0);
+  }
+  assert(A::count == 0);
+  assert(globalMemCounter.checkOutstandingNewEq(0));
+  {
     std::function<int(int)> f = g;
     assert(globalMemCounter.checkOutstandingNewEq(0));
-    assert(f.target<int(*)(int)>());
+    assert(f.target<int (*)(int)>());
     assert(f.target<A>() == 0);
     std::function<int(int)> f2;
     f2 = f;
     assert(globalMemCounter.checkOutstandingNewEq(0));
-    assert(f2.target<int(*)(int)>());
+    assert(f2.target<int (*)(int)>());
     assert(f2.target<A>() == 0);
-    }
-    assert(globalMemCounter.checkOutstandingNewEq(0));
-    {
+  }
+  assert(globalMemCounter.checkOutstandingNewEq(0));
+  {
     std::function<int(int)> f;
     assert(globalMemCounter.checkOutstandingNewEq(0));
-    assert(f.target<int(*)(int)>() == 0);
+    assert(f.target<int (*)(int)>() == 0);
     assert(f.target<A>() == 0);
     std::function<int(int)> f2;
     f2 = f;
     assert(globalMemCounter.checkOutstandingNewEq(0));
-    assert(f2.target<int(*)(int)>() == 0);
+    assert(f2.target<int (*)(int)>() == 0);
     assert(f2.target<A>() == 0);
-    }
+  }
+  {
+    typedef std::function<int()> Func;
+    Func f = g0;
+    Func& fr = (f = f);
+    assert(&fr == &f);
+    assert(*f.target<int(*)()>() == g0);
+  }
+  {
+    typedef std::function<int(int)> Func;
+    Func f = g;
+    Func& fr = (f = f);
+    assert(&fr == &f);
+    assert(*f.target<int(*)(int)>() == g);
+  }
+  {
+    typedef std::function<int(int, int)> Func;
+    Func f = g2;
+    Func& fr = (f = f);
+    assert(&fr == &f);
+    assert(*f.target<int(*)(int, int)>() == g2);
+  }
+  {
+    typedef std::function<int(int, int, int)> Func;
+    Func f = g3;
+    Func& fr = (f = f);
+    assert(&fr == &f);
+    assert(*f.target<int(*)(int, int, int)>() == g3);
+  }
 #if TEST_STD_VER >= 11
-    assert(globalMemCounter.checkOutstandingNewEq(0));
-    {
+  assert(globalMemCounter.checkOutstandingNewEq(0));
+  {
     std::function<int(int)> f = A();
     assert(A::count == 1);
     assert(globalMemCounter.checkOutstandingNewEq(1));
     assert(f.target<A>());
-    assert(f.target<int(*)(int)>() == 0);
+    assert(f.target<int (*)(int)>() == 0);
     std::function<int(int)> f2;
     f2 = std::move(f);
     assert(A::count == 1);
     assert(globalMemCounter.checkOutstandingNewEq(1));
     assert(f2.target<A>());
-    assert(f2.target<int(*)(int)>() == 0);
+    assert(f2.target<int (*)(int)>() == 0);
     assert(f.target<A>() == 0);
-    assert(f.target<int(*)(int)>() == 0);
-    }
+    assert(f.target<int (*)(int)>() == 0);
+  }
 #endif
 }

Modified: libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.mod/swap.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.mod/swap.pass.cpp?rev=290721&r1=290720&r2=290721&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.mod/swap.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.mod/swap.pass.cpp Thu Dec 29 14:03:55 2016
@@ -18,46 +18,49 @@
 
 #include "count_new.hpp"
 
-class A
-{
-    int data_[10];
-public:
-    static int count;
-
-    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];
-    }
+class A {
+  int data_[10];
 
-    ~A() {--count;}
+public:
+  static int count;
 
-    int operator()(int i) const
-    {
-        for (int j = 0; j < 10; ++j)
-            i += data_[j];
-        return i;
-    }
+  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() { --count; }
+
+  int operator()(int i) const {
+    for (int j = 0; j < 10; ++j)
+      i += data_[j];
+    return i;
+  }
+
+  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 id() const { return data_[0]; }
 };
 
 int A::count = 0;
 
-int g(int) {return 0;}
-int h(int) {return 1;}
-
-int main()
-{
-    assert(globalMemCounter.checkOutstandingNewEq(0));
-    {
+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));
+  {
     std::function<int(int)> f1 = A(1);
     std::function<int(int)> f2 = A(2);
     assert(A::count == 2);
@@ -69,52 +72,122 @@ int main()
     assert(globalMemCounter.checkOutstandingNewEq(2));
     assert(f1.target<A>()->id() == 2);
     assert(f2.target<A>()->id() == 1);
-    }
-    assert(A::count == 0);
-    assert(globalMemCounter.checkOutstandingNewEq(0));
-    {
+  }
+  assert(A::count == 0);
+  assert(globalMemCounter.checkOutstandingNewEq(0));
+  {
     std::function<int(int)> f1 = A(1);
     std::function<int(int)> f2 = g;
     assert(A::count == 1);
     assert(globalMemCounter.checkOutstandingNewEq(1));
     assert(f1.target<A>()->id() == 1);
-    assert(*f2.target<int(*)(int)>() == g);
+    assert(*f2.target<int (*)(int)>() == g);
     f1.swap(f2);
     assert(A::count == 1);
     assert(globalMemCounter.checkOutstandingNewEq(1));
-    assert(*f1.target<int(*)(int)>() == g);
+    assert(*f1.target<int (*)(int)>() == g);
     assert(f2.target<A>()->id() == 1);
-    }
-    assert(A::count == 0);
-    assert(globalMemCounter.checkOutstandingNewEq(0));
-    {
+  }
+  assert(A::count == 0);
+  assert(globalMemCounter.checkOutstandingNewEq(0));
+  {
     std::function<int(int)> f1 = g;
     std::function<int(int)> f2 = A(1);
     assert(A::count == 1);
     assert(globalMemCounter.checkOutstandingNewEq(1));
-    assert(*f1.target<int(*)(int)>() == g);
+    assert(*f1.target<int (*)(int)>() == g);
     assert(f2.target<A>()->id() == 1);
     f1.swap(f2);
     assert(A::count == 1);
     assert(globalMemCounter.checkOutstandingNewEq(1));
     assert(f1.target<A>()->id() == 1);
-    assert(*f2.target<int(*)(int)>() == g);
-    }
-    assert(A::count == 0);
-    assert(globalMemCounter.checkOutstandingNewEq(0));
-    {
+    assert(*f2.target<int (*)(int)>() == g);
+  }
+  assert(A::count == 0);
+  assert(globalMemCounter.checkOutstandingNewEq(0));
+  {
     std::function<int(int)> f1 = g;
     std::function<int(int)> f2 = h;
     assert(A::count == 0);
     assert(globalMemCounter.checkOutstandingNewEq(0));
-    assert(*f1.target<int(*)(int)>() == g);
-    assert(*f2.target<int(*)(int)>() == h);
+    assert(*f1.target<int (*)(int)>() == g);
+    assert(*f2.target<int (*)(int)>() == h);
     f1.swap(f2);
     assert(A::count == 0);
     assert(globalMemCounter.checkOutstandingNewEq(0));
-    assert(*f1.target<int(*)(int)>() == h);
-    assert(*f2.target<int(*)(int)>() == g);
+    assert(*f1.target<int (*)(int)>() == h);
+    assert(*f2.target<int (*)(int)>() == g);
+  }
+  assert(A::count == 0);
+  assert(globalMemCounter.checkOutstandingNewEq(0));
+  {
+    std::function<int(int)> 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<A>()->id() == 1);
+  }
+  assert(A::count == 0);
+  assert(globalMemCounter.checkOutstandingNewEq(0));
+  {
+    std::function<int()> f1 = g0;
+    DisableAllocationGuard guard;
+    ((void)guard);
+    f1.swap(f1);
+    assert(*f1.target<int (*)()>() == g0);
+  }
+  assert(globalMemCounter.checkOutstandingNewEq(0));
+  {
+    std::function<int(int, int)> f1 = g2;
+    DisableAllocationGuard guard;
+    ((void)guard);
+    f1.swap(f1);
+    assert(*f1.target<int (*)(int, int)>() == g2);
+  }
+  assert(globalMemCounter.checkOutstandingNewEq(0));
+  {
+    std::function<int(int, int, int)> f1 = g3;
+    DisableAllocationGuard guard;
+    ((void)guard);
+    f1.swap(f1);
+    assert(*f1.target<int (*)(int, int, int)>() == g3);
+  }
+  assert(globalMemCounter.checkOutstandingNewEq(0));
+  {
+    std::function<int()> f1 = A(1);
+    assert(A::count == 1);
+    DisableAllocationGuard guard;
+    ((void)guard);
+    f1.swap(f1);
+    assert(A::count == 1);
+    assert(f1.target<A>()->id() == 1);
+  }
+  assert(globalMemCounter.checkOutstandingNewEq(0));
+  assert(A::count == 0);
+  {
+    std::function<int(int, int)> f1 = A(2);
+    assert(A::count == 1);
+    DisableAllocationGuard guard;
+    ((void)guard);
+    f1.swap(f1);
+    assert(A::count == 1);
+    assert(f1.target<A>()->id() == 2);
+  }
+  assert(globalMemCounter.checkOutstandingNewEq(0));
+  assert(A::count == 0);
+  {
+    std::function<int(int, int, int)> f1 = A(3);
+    assert(A::count == 1);
+    DisableAllocationGuard guard;
+    ((void)guard);
+    f1.swap(f1);
+    assert(A::count == 1);
+    assert(f1.target<A>()->id() == 3);
+  }
+  assert(globalMemCounter.checkOutstandingNewEq(0));
+  assert(A::count == 0);
 }




More information about the cfe-commits mailing list