Skip to content

Commit 0620a68

Browse files
committed
saved_handler destroys handler if cancellation_slot::emplace throws
1 parent ad2c9a3 commit 0620a68

File tree

1 file changed

+66
-37
lines changed

1 file changed

+66
-37
lines changed

include/boost/beast/core/impl/saved_handler.hpp

Lines changed: 66 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,70 @@ class saved_handler::impl final : public base
5252
using alloc_traits =
5353
beast::detail::allocator_traits<alloc_type>;
5454

55-
struct storage
55+
class cancel_op
5656
{
57-
alloc_type a;
58-
impl* p;
57+
impl* p_;
58+
net::cancellation_type accepted_ct_;
5959

60+
public:
61+
cancel_op(impl* p, net::cancellation_type accepted_ct)
62+
: p_(p)
63+
, accepted_ct_(accepted_ct)
64+
{
65+
}
66+
67+
void
68+
operator()(net::cancellation_type ct)
69+
{
70+
if((ct & accepted_ct_) != net::cancellation_type::none)
71+
p_->self_complete();
72+
}
73+
};
74+
75+
class storage
76+
{
77+
alloc_type a_;
78+
impl* p_;
79+
bool c_;
80+
81+
public:
6082
explicit
61-
storage(Alloc const& a_)
62-
: a(a_)
63-
, p(alloc_traits::allocate(a, 1))
83+
storage(Alloc const& a)
84+
: a_(a)
85+
, p_(alloc_traits::allocate(a_, 1))
86+
, c_(false)
6487
{
6588
}
6689

90+
template<class Handler_>
91+
void
92+
construct(Handler_&& h, saved_handler* owner)
93+
{
94+
alloc_traits::construct(
95+
a_, p_, a_, std::forward<Handler_>(h), owner);
96+
c_ = true;
97+
}
98+
99+
impl*
100+
get() noexcept
101+
{
102+
return p_;
103+
}
104+
105+
impl*
106+
release() noexcept
107+
{
108+
return boost::exchange(p_, nullptr);
109+
}
110+
67111
~storage()
68112
{
69-
if(p)
70-
alloc_traits::deallocate(a, p, 1);
113+
if(p_)
114+
{
115+
if(c_)
116+
alloc_traits::destroy(a_, p_);
117+
alloc_traits::deallocate(a_, p_, 1);
118+
}
71119
}
72120
};
73121

@@ -138,45 +186,26 @@ class saved_handler::impl final : public base
138186
template<class Handler, class Allocator>
139187
void
140188
saved_handler::
141-
emplace(Handler&& handler, Allocator const& alloc,
142-
net::cancellation_type cancel_type)
189+
emplace(
190+
Handler&& handler,
191+
Allocator const& alloc,
192+
net::cancellation_type cancel_type)
143193
{
144194
// Can't delete a handler before invoking
145195
BOOST_ASSERT(! has_value());
146196
using impl_type =
147197
impl<typename std::decay<Handler>::type, Allocator>;
148198

149199
typename impl_type::storage s(alloc);
150-
impl_type::alloc_traits::construct(s.a, s.p,
151-
s.a, std::forward<Handler>(handler), this);
152-
153-
auto tmp = boost::exchange(s.p, nullptr);
154-
p_ = tmp;
200+
auto c_slot = net::get_associated_cancellation_slot(handler);
155201

156-
auto c_slot = net::get_associated_cancellation_slot(tmp->v_.h);
157-
if (c_slot.is_connected())
158-
{
159-
class cancel_op
160-
{
161-
impl_type* p_;
162-
net::cancellation_type accepted_ct_;
202+
s.construct(std::forward<Handler>(handler), this);
163203

164-
public:
165-
cancel_op(impl_type* p, net::cancellation_type accepted_ct)
166-
: p_(p)
167-
, accepted_ct_(accepted_ct)
168-
{
169-
}
204+
if(c_slot.is_connected())
205+
c_slot.template emplace<
206+
typename impl_type::cancel_op>(s.get(), cancel_type);
170207

171-
void
172-
operator()(net::cancellation_type ct)
173-
{
174-
if((ct & accepted_ct_) != net::cancellation_type::none)
175-
p_->self_complete();
176-
}
177-
};
178-
c_slot.template emplace<cancel_op>(tmp, cancel_type);
179-
}
208+
p_ = s.release();
180209
}
181210

182211
template<class Handler>

0 commit comments

Comments
 (0)