* [PATCH] PR libstdc++/80316 make promise::set_value throw no_state error
@ 2017-04-04 19:44 Jonathan Wakely
2017-04-21 18:47 ` Jonathan Wakely
0 siblings, 1 reply; 7+ messages in thread
From: Jonathan Wakely @ 2017-04-04 19:44 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 1603 bytes --]
We got a bug report from a customer pointing out that calling
promise::set_value on a moved-from promise crashes instead of throwing
an exception with error code future_errc::no_state.
This fixes it, by moving the _S_check calls to *before* we deference
the pointer that the calls check!
This passes all tests, including the more comprehensive ones I've
added as part of this commit, but I think it can wait for stage 1
anyway. We've been shipping this bug for a couple of releases already.
PR libstdc++/80316
* include/std/future (_State_baseV2::_Setter::operator()): Remove
_S_check calls that are done after the pointer to the shared state is
already dereferenced.
(_State_baseV2::_Setter<_Res, void>): Define specialization for void
as partial specialization so it can be defined within the definition
of _State_baseV2.
(_State_baseV2::__setter): Call _S_check.
(_State_baseV2::__setter(promise<void>*)): Add overload for use by
promise<void>::set_value and promise<void>::set_value_at_thread_exit.
(promise<T>, promise<T&>, promise<void>): Make _State a friend.
(_State_baseV2::_Setter<void, void>): Remove explicit specialization.
(promise<void>::set_value, promise<void>::set_value_at_thread_exit):
Use new __setter overload.
* testsuite/30_threads/promise/members/at_thread_exit2.cc: New test.
* testsuite/30_threads/promise/members/set_exception.cc: Test
promise<T&> and promise<void> specializations.
* testsuite/30_threads/promise/members/set_exception2.cc: Likewise.
Test for no_state error condition.
* testsuite/30_threads/promise/members/set_value2.cc: Likewise.
[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 21856 bytes --]
commit 83c1e45d0759dd095c7b35d67fb5ba98dc7bf909
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Tue Apr 4 19:48:33 2017 +0100
PR libstdc++/80316 make promise::set_value throw no_state error
PR libstdc++/80316
* include/std/future (_State_baseV2::_Setter::operator()): Remove
_S_check calls that are done after the pointer to the shared state is
already dereferenced.
(_State_baseV2::_Setter<_Res, void>): Define specialization for void
as partial specialization so it can be defined within the definition
of _State_baseV2.
(_State_baseV2::__setter): Call _S_check.
(_State_baseV2::__setter(promise<void>*)): Add overload for use by
promise<void>::set_value and promise<void>::set_value_at_thread_exit.
(promise<T>, promise<T&>, promise<void>): Make _State a friend.
(_State_baseV2::_Setter<void, void>): Remove explicit specialization.
(promise<void>::set_value, promise<void>::set_value_at_thread_exit):
Use new __setter overload.
* testsuite/30_threads/promise/members/at_thread_exit2.cc: New test.
* testsuite/30_threads/promise/members/set_exception.cc: Test
promise<T&> and promise<void> specializations.
* testsuite/30_threads/promise/members/set_exception2.cc: Likewise.
Test for no_state error condition.
* testsuite/30_threads/promise/members/set_value2.cc: Likewise.
diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future
index cb53561..73d5a60 100644
--- a/libstdc++-v3/include/std/future
+++ b/libstdc++-v3/include/std/future
@@ -471,7 +471,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Used by std::promise to copy construct the result.
typename promise<_Res>::_Ptr_type operator()() const
{
- _State_baseV2::_S_check(_M_promise->_M_future);
_M_promise->_M_storage->_M_set(*_M_arg);
return std::move(_M_promise->_M_storage);
}
@@ -486,7 +485,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Used by std::promise to move construct the result.
typename promise<_Res>::_Ptr_type operator()() const
{
- _State_baseV2::_S_check(_M_promise->_M_future);
_M_promise->_M_storage->_M_set(std::move(*_M_arg));
return std::move(_M_promise->_M_storage);
}
@@ -494,6 +492,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Res* _M_arg;
};
+ // set void
+ template<typename _Res>
+ struct _Setter<_Res, void>
+ {
+ static_assert(is_void<_Res>::value, "Only used for promise<void>");
+
+ typename promise<_Res>::_Ptr_type operator()() const
+ { return std::move(_M_promise->_M_storage); }
+
+ promise<_Res>* _M_promise;
+ };
+
struct __exception_ptr_tag { };
// set exceptions
@@ -503,7 +513,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Used by std::promise to store an exception as the result.
typename promise<_Res>::_Ptr_type operator()() const
{
- _State_baseV2::_S_check(_M_promise->_M_future);
_M_promise->_M_storage->_M_error = *_M_ex;
return std::move(_M_promise->_M_storage);
}
@@ -516,6 +525,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
static _Setter<_Res, _Arg&&>
__setter(promise<_Res>* __prom, _Arg&& __arg)
{
+ _S_check(__prom->_M_future);
return _Setter<_Res, _Arg&&>{ __prom, std::__addressof(__arg) };
}
@@ -523,9 +533,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
static _Setter<_Res, __exception_ptr_tag>
__setter(exception_ptr& __ex, promise<_Res>* __prom)
{
+ _S_check(__prom->_M_future);
return _Setter<_Res, __exception_ptr_tag>{ __prom, &__ex };
}
+ template<typename _Res>
+ static _Setter<_Res, void>
+ __setter(promise<_Res>* __prom)
+ {
+ _S_check(__prom->_M_future);
+ return _Setter<_Res, void>{ __prom };
+ }
+
template<typename _Tp>
static void
_S_check(const shared_ptr<_Tp>& __p)
@@ -1027,6 +1046,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typedef __future_base::_Result<_Res> _Res_type;
typedef __future_base::_Ptr<_Res_type> _Ptr_type;
template<typename, typename> friend class _State::_Setter;
+ friend _State;
shared_ptr<_State> _M_future;
_Ptr_type _M_storage;
@@ -1137,6 +1157,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typedef __future_base::_Result<_Res&> _Res_type;
typedef __future_base::_Ptr<_Res_type> _Ptr_type;
template<typename, typename> friend class _State::_Setter;
+ friend _State;
shared_ptr<_State> _M_future;
_Ptr_type _M_storage;
@@ -1226,6 +1247,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typedef __future_base::_Result<void> _Res_type;
typedef __future_base::_Ptr<_Res_type> _Ptr_type;
template<typename, typename> friend class _State::_Setter;
+ friend _State;
shared_ptr<_State> _M_future;
_Ptr_type _M_storage;
@@ -1286,14 +1308,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return future<void>(_M_future); }
// Setting the result
- void set_value();
+ void
+ set_value()
+ { _M_future->_M_set_result(_State::__setter(this)); }
void
set_exception(exception_ptr __p)
{ _M_future->_M_set_result(_State::__setter(__p, this)); }
void
- set_value_at_thread_exit();
+ set_value_at_thread_exit()
+ { _M_future->_M_set_delayed_result(_State::__setter(this), _M_future); }
void
set_exception_at_thread_exit(exception_ptr __p)
@@ -1303,30 +1328,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
};
- // set void
- template<>
- struct __future_base::_State_base::_Setter<void, void>
- {
- promise<void>::_Ptr_type operator()() const
- {
- _State_base::_S_check(_M_promise->_M_future);
- return std::move(_M_promise->_M_storage);
- }
-
- promise<void>* _M_promise;
- };
-
- inline void
- promise<void>::set_value()
- { _M_future->_M_set_result(_State::_Setter<void, void>{ this }); }
-
- inline void
- promise<void>::set_value_at_thread_exit()
- {
- _M_future->_M_set_delayed_result(_State::_Setter<void, void>{this},
- _M_future);
- }
-
template<typename _Ptr_type, typename _Fn, typename _Res>
struct __future_base::_Task_setter
{
diff --git a/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc b/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc
new file mode 100644
index 0000000..9429a99
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc
@@ -0,0 +1,167 @@
+// { dg-do run { target *-*-freebsd* *-*-dragonfly* *-*-netbsd* *-*-linux* *-*-gnu* *-*-solaris* *-*-cygwin *-*-rtems* *-*-darwin* powerpc-ibm-aix* } }
+// { dg-options "-pthread" { target *-*-freebsd* *-*-dragonfly* *-*-netbsd* *-*-linux* *-*-gnu* *-*-solaris* powerpc-ibm-aix* } }
+// { dg-require-effective-target c++11 }
+// { dg-require-cstdint "" }
+// { dg-require-gthreads "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// Test set_value_at_thread_exit error conditions
+
+#include <future>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ std::promise<int> p1;
+ p1.set_value(1);
+ try
+ {
+ p1.set_value_at_thread_exit(2);
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY( e.code() == std::future_errc::promise_already_satisfied );
+ }
+ try
+ {
+ p1.set_exception_at_thread_exit(std::make_exception_ptr(3));
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY( e.code() == std::future_errc::promise_already_satisfied );
+ }
+
+ std::promise<int> p2(std::move(p1));
+ try
+ {
+ p1.set_value_at_thread_exit(2);
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY( e.code() == std::future_errc::no_state );
+ }
+ try
+ {
+ p1.set_exception_at_thread_exit(std::make_exception_ptr(3));
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY( e.code() == std::future_errc::no_state );
+ }
+}
+
+void test02()
+{
+ std::promise<int&> p1;
+ int i = 1;
+ p1.set_value(i);
+ try
+ {
+ p1.set_value_at_thread_exit(i);
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY( e.code() == std::future_errc::promise_already_satisfied );
+ }
+ try
+ {
+ p1.set_exception_at_thread_exit(std::make_exception_ptr(3));
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY( e.code() == std::future_errc::promise_already_satisfied );
+ }
+
+ std::promise<int&> p2(std::move(p1));
+ try
+ {
+ int i = 0;
+ p1.set_value_at_thread_exit(i);
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY( e.code() == std::future_errc::no_state );
+ }
+ try
+ {
+ p1.set_exception_at_thread_exit(std::make_exception_ptr(3));
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY( e.code() == std::future_errc::no_state );
+ }
+}
+
+void test03()
+{
+ std::promise<void> p1;
+ int i = 0;
+ p1.set_value();
+ try {
+ p1.set_value_at_thread_exit();
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY( e.code() == std::future_errc::promise_already_satisfied );
+ }
+ try
+ {
+ p1.set_exception_at_thread_exit(std::make_exception_ptr(3));
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY( e.code() == std::future_errc::promise_already_satisfied );
+ }
+
+ std::promise<void> p2(std::move(p1));
+ try {
+ p1.set_value_at_thread_exit();
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY( e.code() == std::future_errc::no_state );
+ }
+ try
+ {
+ p1.set_exception_at_thread_exit(std::make_exception_ptr(3));
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY( e.code() == std::future_errc::no_state );
+ }
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/promise/members/set_exception.cc b/libstdc++-v3/testsuite/30_threads/promise/members/set_exception.cc
index 6ff4a34..4646e38 100644
--- a/libstdc++-v3/testsuite/30_threads/promise/members/set_exception.cc
+++ b/libstdc++-v3/testsuite/30_threads/promise/members/set_exception.cc
@@ -21,6 +21,7 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
+// Test that promise::set_exception stores an exception.
#include <future>
#include <testsuite_hooks.h>
@@ -48,8 +49,56 @@ void test01()
VERIFY( !f1.valid() );
}
+void test02()
+{
+ bool test = false;
+
+ std::promise<int&> p1;
+ std::future<int&> f1 = p1.get_future();
+
+ VERIFY( f1.valid() );
+
+ p1.set_exception(std::make_exception_ptr(0));
+
+ try
+ {
+ f1.get();
+ }
+ catch (int)
+ {
+ test = true;
+ }
+ VERIFY( test );
+ VERIFY( !f1.valid() );
+}
+
+void test03()
+{
+ bool test = false;
+
+ std::promise<void> p1;
+ std::future<void> f1 = p1.get_future();
+
+ VERIFY( f1.valid() );
+
+ p1.set_exception(std::make_exception_ptr(0));
+
+ try
+ {
+ f1.get();
+ }
+ catch (int)
+ {
+ test = true;
+ }
+ VERIFY( test );
+ VERIFY( !f1.valid() );
+}
+
int main()
{
test01();
+ test02();
+ test03();
return 0;
}
diff --git a/libstdc++-v3/testsuite/30_threads/promise/members/set_exception2.cc b/libstdc++-v3/testsuite/30_threads/promise/members/set_exception2.cc
index 1b1a066..dc2c4a8 100644
--- a/libstdc++-v3/testsuite/30_threads/promise/members/set_exception2.cc
+++ b/libstdc++-v3/testsuite/30_threads/promise/members/set_exception2.cc
@@ -21,10 +21,13 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
+// Test that promise::set_exception throws when required.
#include <future>
#include <testsuite_hooks.h>
+// Check for promise_already_satisfied error conditions.
+
void test01()
{
bool test = false;
@@ -83,9 +86,187 @@ void test02()
VERIFY( test );
}
+void test03()
+{
+ bool test = false;
+
+ std::promise<int&> p1;
+ std::future<int&> f1 = p1.get_future();
+
+ p1.set_exception(std::make_exception_ptr(0));
+
+ try
+ {
+ p1.set_exception(std::make_exception_ptr(1));
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY(e.code() ==
+ std::make_error_code(std::future_errc::promise_already_satisfied));
+ test = true;
+ }
+
+ try
+ {
+ f1.get();
+ test = false;
+ }
+ catch(int i)
+ {
+ VERIFY( i == 0 );
+ }
+
+ VERIFY( test );
+}
+
+void test04()
+{
+ bool test = false;
+
+ std::promise<int&> p1;
+ std::future<int&> f1 = p1.get_future();
+
+ int i = 2;
+ p1.set_value(i);
+
+ try
+ {
+ p1.set_exception(std::make_exception_ptr(0));
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY(e.code() ==
+ std::make_error_code(std::future_errc::promise_already_satisfied));
+ test = true;
+ }
+
+ VERIFY( test );
+}
+
+void test05()
+{
+ bool test = false;
+
+ std::promise<void> p1;
+ std::future<void> f1 = p1.get_future();
+
+ p1.set_exception(std::make_exception_ptr(0));
+
+ try
+ {
+ p1.set_exception(std::make_exception_ptr(1));
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY(e.code() ==
+ std::make_error_code(std::future_errc::promise_already_satisfied));
+ test = true;
+ }
+
+ try
+ {
+ f1.get();
+ test = false;
+ }
+ catch(int i)
+ {
+ VERIFY( i == 0 );
+ }
+
+ VERIFY( test );
+}
+
+void test06()
+{
+ bool test = false;
+
+ std::promise<void> p1;
+ std::future<void> f1 = p1.get_future();
+
+ p1.set_value();
+
+ try
+ {
+ p1.set_exception(std::make_exception_ptr(0));
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY(e.code() ==
+ std::make_error_code(std::future_errc::promise_already_satisfied));
+ test = true;
+ }
+
+ VERIFY( test );
+}
+
+// Check for no_state error condition (PR libstdc++/80316)
+
+void test07()
+{
+ using namespace std;
+
+ promise<int> p1;
+ promise<int> p2(std::move(p1));
+ try
+ {
+ p1.set_exception(std::make_exception_ptr(1));
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY(e.code() == make_error_code(future_errc::no_state));
+ }
+}
+
+void test08()
+{
+ using namespace std;
+
+ promise<int&> p1;
+ promise<int&> p2(std::move(p1));
+ try
+ {
+ int i = 0;
+ p1.set_exception(std::make_exception_ptr(1));
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY(e.code() == make_error_code(future_errc::no_state));
+ }
+}
+
+void test09()
+{
+ using namespace std;
+
+ promise<void> p1;
+ promise<void> p2(std::move(p1));
+ try
+ {
+ p1.set_exception(std::make_exception_ptr(1));
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY(e.code() == make_error_code(future_errc::no_state));
+ }
+}
+
int main()
{
test01();
test02();
+ test03();
+ test04();
+ test05();
+ test06();
+ test07();
+ test08();
+ test09();
return 0;
}
diff --git a/libstdc++-v3/testsuite/30_threads/promise/members/set_value2.cc b/libstdc++-v3/testsuite/30_threads/promise/members/set_value2.cc
index 0c4e87a..33c8ed9 100644
--- a/libstdc++-v3/testsuite/30_threads/promise/members/set_value2.cc
+++ b/libstdc++-v3/testsuite/30_threads/promise/members/set_value2.cc
@@ -21,10 +21,13 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
+// Test that promise::set_value throws when required.
#include <future>
#include <testsuite_hooks.h>
+// Check for promise_already_satisfied error conditions.
+
void test01()
{
bool test = false;
@@ -79,9 +82,298 @@ void test02()
VERIFY( test );
}
+void test03()
+{
+ bool test = false;
+
+ std::promise<int> p1;
+ std::future<int> f1 = p1.get_future();
+
+ p1.set_exception(std::make_exception_ptr(4));
+
+ try
+ {
+ p1.set_value(3);
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY(e.code() ==
+ std::make_error_code(std::future_errc::promise_already_satisfied));
+ test = true;
+ }
+
+ std::chrono::milliseconds delay(1);
+ VERIFY( f1.wait_for(delay) == std::future_status::ready );
+ test = false;
+ try
+ {
+ f1.get();
+ VERIFY( false );
+ }
+ catch (int e)
+ {
+ VERIFY(e == 4 );
+ test = true;
+ }
+
+ VERIFY( test );
+}
+
+void test04()
+{
+ bool test = false;
+
+ std::promise<int&> p1;
+ std::future<int&> f1 = p1.get_future();
+
+ int i = 1;
+ p1.set_value(i);
+
+ try
+ {
+ p1.set_value(i);
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY(e.code() ==
+ std::make_error_code(std::future_errc::promise_already_satisfied));
+ test = true;
+ }
+
+ std::chrono::milliseconds delay(1);
+ VERIFY( f1.wait_for(delay) == std::future_status::ready );
+ VERIFY( f1.get() == 1 );
+ VERIFY( test );
+}
+
+void test05()
+{
+ bool test = false;
+
+ std::promise<int&> p1;
+ std::future<int&> f1 = p1.get_future();
+
+ int i = 3;
+ p1.set_value(i);
+
+ try
+ {
+ p1.set_exception(std::make_exception_ptr(4));
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY(e.code() ==
+ std::make_error_code(std::future_errc::promise_already_satisfied));
+ test = true;
+ }
+
+ std::chrono::milliseconds delay(1);
+ VERIFY( f1.wait_for(delay) == std::future_status::ready );
+ VERIFY( f1.get() == 3 );
+ VERIFY( test );
+}
+
+void test06()
+{
+ bool test = false;
+
+ std::promise<int&> p1;
+ std::future<int&> f1 = p1.get_future();
+
+ p1.set_exception(std::make_exception_ptr(4));
+
+ try
+ {
+ int i = 3;
+ p1.set_value(i);
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY(e.code() ==
+ std::make_error_code(std::future_errc::promise_already_satisfied));
+ test = true;
+ }
+
+ std::chrono::milliseconds delay(1);
+ VERIFY( f1.wait_for(delay) == std::future_status::ready );
+ test = false;
+ try
+ {
+ f1.get();
+ VERIFY( false );
+ }
+ catch (int e)
+ {
+ VERIFY(e == 4 );
+ test = true;
+ }
+
+ VERIFY( test );
+}
+
+void test07()
+{
+ bool test = false;
+
+ std::promise<void> p1;
+ std::future<void> f1 = p1.get_future();
+
+ p1.set_value();
+
+ try
+ {
+ p1.set_value();
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY(e.code() ==
+ std::make_error_code(std::future_errc::promise_already_satisfied));
+ test = true;
+ }
+
+ std::chrono::milliseconds delay(1);
+ VERIFY( f1.wait_for(delay) == std::future_status::ready );
+ f1.get();
+ VERIFY( test );
+}
+
+void test08()
+{
+ bool test = false;
+
+ std::promise<void> p1;
+ std::future<void> f1 = p1.get_future();
+
+ p1.set_value();
+
+ try
+ {
+ p1.set_exception(std::make_exception_ptr(4));
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY(e.code() ==
+ std::make_error_code(std::future_errc::promise_already_satisfied));
+ test = true;
+ }
+
+ std::chrono::milliseconds delay(1);
+ VERIFY( f1.wait_for(delay) == std::future_status::ready );
+ f1.get();
+ VERIFY( test );
+}
+
+void test09()
+{
+ bool test = false;
+
+ std::promise<void> p1;
+ std::future<void> f1 = p1.get_future();
+
+ p1.set_exception(std::make_exception_ptr(4));
+
+ try
+ {
+ p1.set_value();
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY(e.code() ==
+ std::make_error_code(std::future_errc::promise_already_satisfied));
+ test = true;
+ }
+
+ std::chrono::milliseconds delay(1);
+ VERIFY( f1.wait_for(delay) == std::future_status::ready );
+ test = false;
+ try
+ {
+ f1.get();
+ VERIFY( false );
+ }
+ catch (int e)
+ {
+ VERIFY(e == 4 );
+ test = true;
+ }
+
+ VERIFY( test );
+}
+
+// Check for no_state error condition (PR libstdc++/80316)
+
+void test10()
+{
+ using namespace std;
+
+ promise<int> p1;
+ promise<int> p2(std::move(p1));
+ try
+ {
+ p1.set_value(1);
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY(e.code() == make_error_code(future_errc::no_state));
+ }
+}
+
+void test11()
+{
+ using namespace std;
+
+ promise<int&> p1;
+ promise<int&> p2(std::move(p1));
+ try
+ {
+ int i = 0;
+ p1.set_value(i);
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY(e.code() == make_error_code(future_errc::no_state));
+ }
+}
+
+void test12()
+{
+ using namespace std;
+
+ promise<void> p1;
+ promise<void> p2(std::move(p1));
+ try
+ {
+ p1.set_value();
+ VERIFY( false );
+ }
+ catch (std::future_error& e)
+ {
+ VERIFY(e.code() == make_error_code(future_errc::no_state));
+ }
+}
+
int main()
{
test01();
test02();
+ test03();
+ test04();
+ test05();
+ test06();
+ test07();
+ test08();
+ test09();
+ test10();
+ test11();
+ test12();
return 0;
}
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] PR libstdc++/80316 make promise::set_value throw no_state error
2017-04-04 19:44 [PATCH] PR libstdc++/80316 make promise::set_value throw no_state error Jonathan Wakely
@ 2017-04-21 18:47 ` Jonathan Wakely
2017-07-11 11:53 ` Jonathan Wakely
0 siblings, 1 reply; 7+ messages in thread
From: Jonathan Wakely @ 2017-04-21 18:47 UTC (permalink / raw)
To: libstdc++, gcc-patches
On 4 April 2017 at 20:44, Jonathan Wakely wrote:
> We got a bug report from a customer pointing out that calling
> promise::set_value on a moved-from promise crashes instead of throwing
> an exception with error code future_errc::no_state.
>
> This fixes it, by moving the _S_check calls to *before* we deference
> the pointer that the calls check!
>
> This passes all tests, including the more comprehensive ones I've
> added as part of this commit, but I think it can wait for stage 1
> anyway. We've been shipping this bug for a couple of releases already.
>
> PR libstdc++/80316
> * include/std/future (_State_baseV2::_Setter::operator()): Remove
> _S_check calls that are done after the pointer to the shared state
> is
> already dereferenced.
> (_State_baseV2::_Setter<_Res, void>): Define specialization for void
> as partial specialization so it can be defined within the definition
> of _State_baseV2.
> (_State_baseV2::__setter): Call _S_check.
> (_State_baseV2::__setter(promise<void>*)): Add overload for use by
> promise<void>::set_value and
> promise<void>::set_value_at_thread_exit.
> (promise<T>, promise<T&>, promise<void>): Make _State a friend.
> (_State_baseV2::_Setter<void, void>): Remove explicit
> specialization.
> (promise<void>::set_value, promise<void>::set_value_at_thread_exit):
> Use new __setter overload.
> * testsuite/30_threads/promise/members/at_thread_exit2.cc: New test.
> * testsuite/30_threads/promise/members/set_exception.cc: Test
> promise<T&> and promise<void> specializations.
> * testsuite/30_threads/promise/members/set_exception2.cc: Likewise.
> Test for no_state error condition.
> * testsuite/30_threads/promise/members/set_value2.cc: Likewise.
This is now committed to trunk.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] PR libstdc++/80316 make promise::set_value throw no_state error
2017-04-21 18:47 ` Jonathan Wakely
@ 2017-07-11 11:53 ` Jonathan Wakely
2017-07-11 12:40 ` Jonathan Wakely
0 siblings, 1 reply; 7+ messages in thread
From: Jonathan Wakely @ 2017-07-11 11:53 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: libstdc++, gcc-patches
On 21/04/17 15:54 +0100, Jonathan Wakely wrote:
>On 4 April 2017 at 20:44, Jonathan Wakely wrote:
>> We got a bug report from a customer pointing out that calling
>> promise::set_value on a moved-from promise crashes instead of throwing
>> an exception with error code future_errc::no_state.
>>
>> This fixes it, by moving the _S_check calls to *before* we deference
>> the pointer that the calls check!
>>
>> This passes all tests, including the more comprehensive ones I've
>> added as part of this commit, but I think it can wait for stage 1
>> anyway. We've been shipping this bug for a couple of releases already.
>>
>> PR libstdc++/80316
>> * include/std/future (_State_baseV2::_Setter::operator()): Remove
>> _S_check calls that are done after the pointer to the shared state
>> is
>> already dereferenced.
>> (_State_baseV2::_Setter<_Res, void>): Define specialization for void
>> as partial specialization so it can be defined within the definition
>> of _State_baseV2.
>> (_State_baseV2::__setter): Call _S_check.
>> (_State_baseV2::__setter(promise<void>*)): Add overload for use by
>> promise<void>::set_value and
>> promise<void>::set_value_at_thread_exit.
>> (promise<T>, promise<T&>, promise<void>): Make _State a friend.
>> (_State_baseV2::_Setter<void, void>): Remove explicit
>> specialization.
>> (promise<void>::set_value, promise<void>::set_value_at_thread_exit):
>> Use new __setter overload.
>> * testsuite/30_threads/promise/members/at_thread_exit2.cc: New test.
>> * testsuite/30_threads/promise/members/set_exception.cc: Test
>> promise<T&> and promise<void> specializations.
>> * testsuite/30_threads/promise/members/set_exception2.cc: Likewise.
>> Test for no_state error condition.
>> * testsuite/30_threads/promise/members/set_value2.cc: Likewise.
>
>
>This is now committed to trunk.
And now also to gcc-7-branch.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] PR libstdc++/80316 make promise::set_value throw no_state error
2017-07-11 11:53 ` Jonathan Wakely
@ 2017-07-11 12:40 ` Jonathan Wakely
2017-07-12 7:46 ` Christophe Lyon
0 siblings, 1 reply; 7+ messages in thread
From: Jonathan Wakely @ 2017-07-11 12:40 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: libstdc++, gcc-patches
On 11/07/17 12:53 +0100, Jonathan Wakely wrote:
>On 21/04/17 15:54 +0100, Jonathan Wakely wrote:
>>On 4 April 2017 at 20:44, Jonathan Wakely wrote:
>>>We got a bug report from a customer pointing out that calling
>>>promise::set_value on a moved-from promise crashes instead of throwing
>>>an exception with error code future_errc::no_state.
>>>
>>>This fixes it, by moving the _S_check calls to *before* we deference
>>>the pointer that the calls check!
>>>
>>>This passes all tests, including the more comprehensive ones I've
>>>added as part of this commit, but I think it can wait for stage 1
>>>anyway. We've been shipping this bug for a couple of releases already.
>>>
>>> PR libstdc++/80316
>>> * include/std/future (_State_baseV2::_Setter::operator()): Remove
>>> _S_check calls that are done after the pointer to the shared state
>>>is
>>> already dereferenced.
>>> (_State_baseV2::_Setter<_Res, void>): Define specialization for void
>>> as partial specialization so it can be defined within the definition
>>> of _State_baseV2.
>>> (_State_baseV2::__setter): Call _S_check.
>>> (_State_baseV2::__setter(promise<void>*)): Add overload for use by
>>> promise<void>::set_value and
>>>promise<void>::set_value_at_thread_exit.
>>> (promise<T>, promise<T&>, promise<void>): Make _State a friend.
>>> (_State_baseV2::_Setter<void, void>): Remove explicit
>>>specialization.
>>> (promise<void>::set_value, promise<void>::set_value_at_thread_exit):
>>> Use new __setter overload.
>>> * testsuite/30_threads/promise/members/at_thread_exit2.cc: New test.
>>> * testsuite/30_threads/promise/members/set_exception.cc: Test
>>> promise<T&> and promise<void> specializations.
>>> * testsuite/30_threads/promise/members/set_exception2.cc: Likewise.
>>> Test for no_state error condition.
>>> * testsuite/30_threads/promise/members/set_value2.cc: Likewise.
>>
>>
>>This is now committed to trunk.
>
>And now also to gcc-7-branch.
And gcc-6-branch.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] PR libstdc++/80316 make promise::set_value throw no_state error
2017-07-11 12:40 ` Jonathan Wakely
@ 2017-07-12 7:46 ` Christophe Lyon
2017-07-12 10:15 ` Jonathan Wakely
0 siblings, 1 reply; 7+ messages in thread
From: Christophe Lyon @ 2017-07-12 7:46 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: Jonathan Wakely, libstdc++, gcc-patches
On 11 July 2017 at 14:39, Jonathan Wakely <jwakely@redhat.com> wrote:
> On 11/07/17 12:53 +0100, Jonathan Wakely wrote:
>>
>> On 21/04/17 15:54 +0100, Jonathan Wakely wrote:
>>>
>>> On 4 April 2017 at 20:44, Jonathan Wakely wrote:
>>>>
>>>> We got a bug report from a customer pointing out that calling
>>>> promise::set_value on a moved-from promise crashes instead of throwing
>>>> an exception with error code future_errc::no_state.
>>>>
>>>> This fixes it, by moving the _S_check calls to *before* we deference
>>>> the pointer that the calls check!
>>>>
>>>> This passes all tests, including the more comprehensive ones I've
>>>> added as part of this commit, but I think it can wait for stage 1
>>>> anyway. We've been shipping this bug for a couple of releases already.
>>>>
>>>> PR libstdc++/80316
>>>> * include/std/future (_State_baseV2::_Setter::operator()): Remove
>>>> _S_check calls that are done after the pointer to the shared
>>>> state
>>>> is
>>>> already dereferenced.
>>>> (_State_baseV2::_Setter<_Res, void>): Define specialization for
>>>> void
>>>> as partial specialization so it can be defined within the
>>>> definition
>>>> of _State_baseV2.
>>>> (_State_baseV2::__setter): Call _S_check.
>>>> (_State_baseV2::__setter(promise<void>*)): Add overload for use
>>>> by
>>>> promise<void>::set_value and
>>>> promise<void>::set_value_at_thread_exit.
>>>> (promise<T>, promise<T&>, promise<void>): Make _State a friend.
>>>> (_State_baseV2::_Setter<void, void>): Remove explicit
>>>> specialization.
>>>> (promise<void>::set_value,
>>>> promise<void>::set_value_at_thread_exit):
>>>> Use new __setter overload.
>>>> * testsuite/30_threads/promise/members/at_thread_exit2.cc: New
>>>> test.
>>>> * testsuite/30_threads/promise/members/set_exception.cc: Test
>>>> promise<T&> and promise<void> specializations.
>>>> * testsuite/30_threads/promise/members/set_exception2.cc:
>>>> Likewise.
>>>> Test for no_state error condition.
>>>> * testsuite/30_threads/promise/members/set_value2.cc: Likewise.
>>>
>>>
>>>
>>> This is now committed to trunk.
>>
>>
>> And now also to gcc-7-branch.
>
>
> And gcc-6-branch.
>
Hi Jonathan,
The new test fails to compile on arm when forcing -march=armv5t:
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:
In function 'void test01()':^M
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:31:
error: aggregate 'std::promise<int> p1' has incomplete type and cannot
be defined^M
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:44:
error: 'make_exception_ptr' is not a member of 'std'^M
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:52:
error: variable 'std::promise<int> p2' has initializer but incomplete
type^M
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:64:
error: 'make_exception_ptr' is not a member of 'std'^M
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:
In function 'void test02()':^M
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:75:
error: aggregate 'std::promise<int&> p1' has incomplete type and
cannot be defined^M
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:89:
error: 'make_exception_ptr' is not a member of 'std'^M
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:97:
error: variable 'std::promise<int&> p2' has initializer but incomplete
type^M
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:110:
error: 'make_exception_ptr' is not a member of 'std'^M
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:
In function 'void test03()':^M
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:121:
error: aggregate 'std::promise<void> p1' has incomplete type and
cannot be defined^M
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:134:
error: 'make_exception_ptr' is not a member of 'std'^M
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:142:
error: variable 'std::promise<void> p2' has initializer but incomplete
type^M
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:153:
error: 'make_exception_ptr' is not a member of 'std'^M
compiler exited with status 1
I can see this on target arm-none-linux-gnueabihf --with-mode arm
--with-cpu cortex-a9 --with-fpu vfp and setting -march=armv5t in
runtestflags.
It also looks like you forgot to add a ChangeLog entry for the
testsuite changes.
There is no such error on the gcc-7 branch.
Thanks,
Christophe
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] PR libstdc++/80316 make promise::set_value throw no_state error
2017-07-12 7:46 ` Christophe Lyon
@ 2017-07-12 10:15 ` Jonathan Wakely
2017-07-12 14:49 ` Christophe Lyon
0 siblings, 1 reply; 7+ messages in thread
From: Jonathan Wakely @ 2017-07-12 10:15 UTC (permalink / raw)
To: Christophe Lyon; +Cc: Jonathan Wakely, libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 5820 bytes --]
On 12/07/17 09:46 +0200, Christophe Lyon wrote:
>On 11 July 2017 at 14:39, Jonathan Wakely <jwakely@redhat.com> wrote:
>> On 11/07/17 12:53 +0100, Jonathan Wakely wrote:
>>>
>>> On 21/04/17 15:54 +0100, Jonathan Wakely wrote:
>>>>
>>>> On 4 April 2017 at 20:44, Jonathan Wakely wrote:
>>>>>
>>>>> We got a bug report from a customer pointing out that calling
>>>>> promise::set_value on a moved-from promise crashes instead of throwing
>>>>> an exception with error code future_errc::no_state.
>>>>>
>>>>> This fixes it, by moving the _S_check calls to *before* we deference
>>>>> the pointer that the calls check!
>>>>>
>>>>> This passes all tests, including the more comprehensive ones I've
>>>>> added as part of this commit, but I think it can wait for stage 1
>>>>> anyway. We've been shipping this bug for a couple of releases already.
>>>>>
>>>>> PR libstdc++/80316
>>>>> * include/std/future (_State_baseV2::_Setter::operator()): Remove
>>>>> _S_check calls that are done after the pointer to the shared
>>>>> state
>>>>> is
>>>>> already dereferenced.
>>>>> (_State_baseV2::_Setter<_Res, void>): Define specialization for
>>>>> void
>>>>> as partial specialization so it can be defined within the
>>>>> definition
>>>>> of _State_baseV2.
>>>>> (_State_baseV2::__setter): Call _S_check.
>>>>> (_State_baseV2::__setter(promise<void>*)): Add overload for use
>>>>> by
>>>>> promise<void>::set_value and
>>>>> promise<void>::set_value_at_thread_exit.
>>>>> (promise<T>, promise<T&>, promise<void>): Make _State a friend.
>>>>> (_State_baseV2::_Setter<void, void>): Remove explicit
>>>>> specialization.
>>>>> (promise<void>::set_value,
>>>>> promise<void>::set_value_at_thread_exit):
>>>>> Use new __setter overload.
>>>>> * testsuite/30_threads/promise/members/at_thread_exit2.cc: New
>>>>> test.
>>>>> * testsuite/30_threads/promise/members/set_exception.cc: Test
>>>>> promise<T&> and promise<void> specializations.
>>>>> * testsuite/30_threads/promise/members/set_exception2.cc:
>>>>> Likewise.
>>>>> Test for no_state error condition.
>>>>> * testsuite/30_threads/promise/members/set_value2.cc: Likewise.
>>>>
>>>>
>>>>
>>>> This is now committed to trunk.
>>>
>>>
>>> And now also to gcc-7-branch.
>>
>>
>> And gcc-6-branch.
>>
>
>Hi Jonathan,
>
>The new test fails to compile on arm when forcing -march=armv5t:
>/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:
>In function 'void test01()':^M
>/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:31:
>error: aggregate 'std::promise<int> p1' has incomplete type and cannot
>be defined^M
>/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:44:
>error: 'make_exception_ptr' is not a member of 'std'^M
>/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:52:
>error: variable 'std::promise<int> p2' has initializer but incomplete
>type^M
>/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:64:
>error: 'make_exception_ptr' is not a member of 'std'^M
>/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:
>In function 'void test02()':^M
>/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:75:
>error: aggregate 'std::promise<int&> p1' has incomplete type and
>cannot be defined^M
>/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:89:
>error: 'make_exception_ptr' is not a member of 'std'^M
>/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:97:
>error: variable 'std::promise<int&> p2' has initializer but incomplete
>type^M
>/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:110:
>error: 'make_exception_ptr' is not a member of 'std'^M
>/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:
>In function 'void test03()':^M
>/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:121:
>error: aggregate 'std::promise<void> p1' has incomplete type and
>cannot be defined^M
>/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:134:
>error: 'make_exception_ptr' is not a member of 'std'^M
>/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:142:
>error: variable 'std::promise<void> p2' has initializer but incomplete
>type^M
>/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:153:
>error: 'make_exception_ptr' is not a member of 'std'^M
>compiler exited with status 1
>
>I can see this on target arm-none-linux-gnueabihf --with-mode arm
>--with-cpu cortex-a9 --with-fpu vfp and setting -march=armv5t in
>runtestflags.
>
>It also looks like you forgot to add a ChangeLog entry for the
>testsuite changes.
These changes?
* testsuite/30_threads/promise/members/at_thread_exit2.cc: New test.
* testsuite/30_threads/promise/members/set_exception.cc: Test
promise<T&> and promise<void> specializations.
* testsuite/30_threads/promise/members/set_exception2.cc: Likewise.
Test for no_state error condition.
* testsuite/30_threads/promise/members/set_value2.cc: Likewise.
>There is no such error on the gcc-7 branch.
Because armv5 supports <future> on that branch.
This should fix it, committed to gcc-6-branch.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 847 bytes --]
commit b30c811b2a0ac1497552e153324dd25a65ffa5a7
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Wed Jul 12 11:02:11 2017 +0100
Only run new test on targets that support std::promise
* testsuite/30_threads/promise/members/at_thread_exit2.cc: Require
atomic builtins.
diff --git a/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc b/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc
index 9429a99..a9b0882 100644
--- a/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc
+++ b/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc
@@ -3,6 +3,7 @@
// { dg-require-effective-target c++11 }
// { dg-require-cstdint "" }
// { dg-require-gthreads "" }
+// { dg-require-atomic-builtins "" }
// Copyright (C) 2014-2017 Free Software Foundation, Inc.
//
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] PR libstdc++/80316 make promise::set_value throw no_state error
2017-07-12 10:15 ` Jonathan Wakely
@ 2017-07-12 14:49 ` Christophe Lyon
0 siblings, 0 replies; 7+ messages in thread
From: Christophe Lyon @ 2017-07-12 14:49 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: Jonathan Wakely, libstdc++, gcc-patches
On 12 July 2017 at 12:15, Jonathan Wakely <jwakely@redhat.com> wrote:
> On 12/07/17 09:46 +0200, Christophe Lyon wrote:
>>
>> On 11 July 2017 at 14:39, Jonathan Wakely <jwakely@redhat.com> wrote:
>>>
>>> On 11/07/17 12:53 +0100, Jonathan Wakely wrote:
>>>>
>>>>
>>>> On 21/04/17 15:54 +0100, Jonathan Wakely wrote:
>>>>>
>>>>>
>>>>> On 4 April 2017 at 20:44, Jonathan Wakely wrote:
>>>>>>
>>>>>>
>>>>>> We got a bug report from a customer pointing out that calling
>>>>>> promise::set_value on a moved-from promise crashes instead of throwing
>>>>>> an exception with error code future_errc::no_state.
>>>>>>
>>>>>> This fixes it, by moving the _S_check calls to *before* we deference
>>>>>> the pointer that the calls check!
>>>>>>
>>>>>> This passes all tests, including the more comprehensive ones I've
>>>>>> added as part of this commit, but I think it can wait for stage 1
>>>>>> anyway. We've been shipping this bug for a couple of releases already.
>>>>>>
>>>>>> PR libstdc++/80316
>>>>>> * include/std/future (_State_baseV2::_Setter::operator()):
>>>>>> Remove
>>>>>> _S_check calls that are done after the pointer to the shared
>>>>>> state
>>>>>> is
>>>>>> already dereferenced.
>>>>>> (_State_baseV2::_Setter<_Res, void>): Define specialization for
>>>>>> void
>>>>>> as partial specialization so it can be defined within the
>>>>>> definition
>>>>>> of _State_baseV2.
>>>>>> (_State_baseV2::__setter): Call _S_check.
>>>>>> (_State_baseV2::__setter(promise<void>*)): Add overload for use
>>>>>> by
>>>>>> promise<void>::set_value and
>>>>>> promise<void>::set_value_at_thread_exit.
>>>>>> (promise<T>, promise<T&>, promise<void>): Make _State a friend.
>>>>>> (_State_baseV2::_Setter<void, void>): Remove explicit
>>>>>> specialization.
>>>>>> (promise<void>::set_value,
>>>>>> promise<void>::set_value_at_thread_exit):
>>>>>> Use new __setter overload.
>>>>>> * testsuite/30_threads/promise/members/at_thread_exit2.cc: New
>>>>>> test.
>>>>>> * testsuite/30_threads/promise/members/set_exception.cc: Test
>>>>>> promise<T&> and promise<void> specializations.
>>>>>> * testsuite/30_threads/promise/members/set_exception2.cc:
>>>>>> Likewise.
>>>>>> Test for no_state error condition.
>>>>>> * testsuite/30_threads/promise/members/set_value2.cc: Likewise.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> This is now committed to trunk.
>>>>
>>>>
>>>>
>>>> And now also to gcc-7-branch.
>>>
>>>
>>>
>>> And gcc-6-branch.
>>>
>>
>> Hi Jonathan,
>>
>> The new test fails to compile on arm when forcing -march=armv5t:
>>
>> /aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:
>> In function 'void test01()':^M
>>
>> /aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:31:
>> error: aggregate 'std::promise<int> p1' has incomplete type and cannot
>> be defined^M
>>
>> /aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:44:
>> error: 'make_exception_ptr' is not a member of 'std'^M
>>
>> /aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:52:
>> error: variable 'std::promise<int> p2' has initializer but incomplete
>> type^M
>>
>> /aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:64:
>> error: 'make_exception_ptr' is not a member of 'std'^M
>>
>> /aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:
>> In function 'void test02()':^M
>>
>> /aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:75:
>> error: aggregate 'std::promise<int&> p1' has incomplete type and
>> cannot be defined^M
>>
>> /aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:89:
>> error: 'make_exception_ptr' is not a member of 'std'^M
>>
>> /aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:97:
>> error: variable 'std::promise<int&> p2' has initializer but incomplete
>> type^M
>>
>> /aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:110:
>> error: 'make_exception_ptr' is not a member of 'std'^M
>>
>> /aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:
>> In function 'void test03()':^M
>>
>> /aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:121:
>> error: aggregate 'std::promise<void> p1' has incomplete type and
>> cannot be defined^M
>>
>> /aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:134:
>> error: 'make_exception_ptr' is not a member of 'std'^M
>>
>> /aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:142:
>> error: variable 'std::promise<void> p2' has initializer but incomplete
>> type^M
>>
>> /aci-gcc-fsf/sources/gcc-fsf/gccsrc/libstdc++-v3/testsuite/30_threads/promise/members/at_thread_exit2.cc:153:
>> error: 'make_exception_ptr' is not a member of 'std'^M
>> compiler exited with status 1
>>
>> I can see this on target arm-none-linux-gnueabihf --with-mode arm
>> --with-cpu cortex-a9 --with-fpu vfp and setting -march=armv5t in
>> runtestflags.
>>
>> It also looks like you forgot to add a ChangeLog entry for the
>> testsuite changes.
>
>
> These changes?
Yes
>
> * testsuite/30_threads/promise/members/at_thread_exit2.cc: New test.
> * testsuite/30_threads/promise/members/set_exception.cc: Test
> promise<T&> and promise<void> specializations.
> * testsuite/30_threads/promise/members/set_exception2.cc: Likewise.
> Test for no_state error condition.
> * testsuite/30_threads/promise/members/set_value2.cc: Likewise.
>
>
>> There is no such error on the gcc-7 branch.
>
>
> Because armv5 supports <future> on that branch.
>
> This should fix it, committed to gcc-6-branch.
>
I confirm it's now OK.
Thanks
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2017-07-12 14:49 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-04 19:44 [PATCH] PR libstdc++/80316 make promise::set_value throw no_state error Jonathan Wakely
2017-04-21 18:47 ` Jonathan Wakely
2017-07-11 11:53 ` Jonathan Wakely
2017-07-11 12:40 ` Jonathan Wakely
2017-07-12 7:46 ` Christophe Lyon
2017-07-12 10:15 ` Jonathan Wakely
2017-07-12 14:49 ` Christophe Lyon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).