Fix undefined behavior in pausation

This commit is contained in:
Vinnie Falco
2017-06-02 20:50:11 -07:00
parent 02d5aedc29
commit a38a9adbe1
6 changed files with 15 additions and 25 deletions

View File

@ -2,6 +2,7 @@ Version 47
* Disable operator<< for buffer_body * Disable operator<< for buffer_body
* buffer_size overload for basic_multi_buffer::const_buffers_type * buffer_size overload for basic_multi_buffer::const_buffers_type
* Fix undefined behavior in pausation
API Changes: API Changes:

View File

@ -30,7 +30,7 @@ class pausation
base() = default; base() = default;
base(base &&) = default; base(base &&) = default;
virtual ~base() = default; virtual ~base() = default;
virtual void move(void* p) = 0; virtual base* move(void* p) = 0;
virtual void operator()() = 0; virtual void operator()() = 0;
}; };
@ -48,10 +48,10 @@ class pausation
{ {
} }
void base*
move(void* p) override move(void* p) override
{ {
::new(p) holder(std::move(*this)); return ::new(p) holder(std::move(*this));
} }
void void
@ -100,9 +100,7 @@ public:
{ {
if(other.base_) if(other.base_)
{ {
// type-pun base_ = other.base_->move(buf_);
base_ = reinterpret_cast<base*>(&buf_[0]);
other.base_->move(buf_);
other.base_ = nullptr; other.base_ = nullptr;
} }
} }
@ -117,9 +115,7 @@ public:
if(other.base_) if(other.base_)
{ {
// type-pun base_ = other.base_->move(buf_);
base_ = reinterpret_cast<base*>(&buf_[0]);
other.base_->move(buf_);
other.base_ = nullptr; other.base_ = nullptr;
} }
return *this; return *this;
@ -147,12 +143,11 @@ template<class F>
void void
pausation::emplace(F&& f) pausation::emplace(F&& f)
{ {
static_assert(sizeof(buf_type) >= sizeof(holder<F>), using type = holder<typename std::decay<F>::type>;
static_assert(sizeof(buf_type) >= sizeof(type),
"buffer too small"); "buffer too small");
BOOST_ASSERT(! base_); BOOST_ASSERT(! base_);
::new(buf_) holder<F>(std::forward<F>(f)); base_ = ::new(buf_) type{std::forward<F>(f)};
// type-pun
base_ = reinterpret_cast<base*>(&buf_[0]);
} }
} // detail } // detail

View File

@ -141,8 +141,7 @@ operator()(error_code ec, bool again)
{ {
// suspend // suspend
d.state = 2; d.state = 2;
d.ws.wr_op_.template emplace< d.ws.wr_op_.emplace(std::move(*this));
close_op>(std::move(*this));
return; return;
} }
if(d.ws.failed_ || d.ws.wr_close_) if(d.ws.failed_ || d.ws.wr_close_)

View File

@ -139,8 +139,7 @@ operator()(error_code ec, bool again)
{ {
// suspend // suspend
d.state = 2; d.state = 2;
d.ws.ping_op_.template emplace< d.ws.ping_op_.emplace(std::move(*this));
ping_op>(std::move(*this));
return; return;
} }
if(d.ws.failed_ || d.ws.wr_close_) if(d.ws.failed_ || d.ws.wr_close_)

View File

@ -456,8 +456,7 @@ operator()(error_code ec,
// suspend // suspend
d.state = do_pong_resume; d.state = do_pong_resume;
BOOST_ASSERT(d.ws.wr_block_ != &d); BOOST_ASSERT(d.ws.wr_block_ != &d);
d.ws.rd_op_.template emplace< d.ws.rd_op_.emplace(std::move(*this));
read_frame_op>(std::move(*this));
return; return;
} }
d.state = do_pong; d.state = do_pong;
@ -496,8 +495,7 @@ operator()(error_code ec,
{ {
// suspend // suspend
d.state = do_close_resume; d.state = do_close_resume;
d.ws.rd_op_.template emplace< d.ws.rd_op_.emplace(std::move(*this));
read_frame_op>(std::move(*this));
return; return;
} }
d.state = do_close; d.state = do_close;
@ -630,8 +628,7 @@ operator()(error_code ec,
{ {
// suspend // suspend
d.state = do_fail + 2; d.state = do_fail + 2;
d.ws.rd_op_.template emplace< d.ws.rd_op_.emplace(std::move(*this));
read_frame_op>(std::move(*this));
return; return;
} }
// fall through // fall through

View File

@ -491,8 +491,7 @@ operator()(error_code ec,
{ {
// suspend // suspend
d.state = do_maybe_suspend + 1; d.state = do_maybe_suspend + 1;
d.ws.wr_op_.template emplace< d.ws.wr_op_.emplace(std::move(*this));
write_frame_op>(std::move(*this));
return; return;
} }
if(d.ws.failed_ || d.ws.wr_close_) if(d.ws.failed_ || d.ws.wr_close_)