diff --git a/CHANGELOG.md b/CHANGELOG.md
index cb7eb680..91ed0474 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@ Version 47
* Disable operator<< for buffer_body
* buffer_size overload for basic_multi_buffer::const_buffers_type
+* Fix undefined behavior in pausation
API Changes:
diff --git a/include/beast/websocket/detail/pausation.hpp b/include/beast/websocket/detail/pausation.hpp
index 728a057f..53a99884 100644
--- a/include/beast/websocket/detail/pausation.hpp
+++ b/include/beast/websocket/detail/pausation.hpp
@@ -30,7 +30,7 @@ class pausation
base() = default;
base(base &&) = default;
virtual ~base() = default;
- virtual void move(void* p) = 0;
+ virtual base* move(void* p) = 0;
virtual void operator()() = 0;
};
@@ -48,10 +48,10 @@ class pausation
{
}
- void
+ base*
move(void* p) override
{
- ::new(p) holder(std::move(*this));
+ return ::new(p) holder(std::move(*this));
}
void
@@ -100,9 +100,7 @@ public:
{
if(other.base_)
{
- // type-pun
- base_ = reinterpret_cast(&buf_[0]);
- other.base_->move(buf_);
+ base_ = other.base_->move(buf_);
other.base_ = nullptr;
}
}
@@ -117,9 +115,7 @@ public:
if(other.base_)
{
- // type-pun
- base_ = reinterpret_cast(&buf_[0]);
- other.base_->move(buf_);
+ base_ = other.base_->move(buf_);
other.base_ = nullptr;
}
return *this;
@@ -147,12 +143,11 @@ template
void
pausation::emplace(F&& f)
{
- static_assert(sizeof(buf_type) >= sizeof(holder),
+ using type = holder::type>;
+ static_assert(sizeof(buf_type) >= sizeof(type),
"buffer too small");
BOOST_ASSERT(! base_);
- ::new(buf_) holder(std::forward(f));
- // type-pun
- base_ = reinterpret_cast(&buf_[0]);
+ base_ = ::new(buf_) type{std::forward(f)};
}
} // detail
diff --git a/include/beast/websocket/impl/close.ipp b/include/beast/websocket/impl/close.ipp
index 6b748f20..e6ac1083 100644
--- a/include/beast/websocket/impl/close.ipp
+++ b/include/beast/websocket/impl/close.ipp
@@ -141,8 +141,7 @@ operator()(error_code ec, bool again)
{
// suspend
d.state = 2;
- d.ws.wr_op_.template emplace<
- close_op>(std::move(*this));
+ d.ws.wr_op_.emplace(std::move(*this));
return;
}
if(d.ws.failed_ || d.ws.wr_close_)
diff --git a/include/beast/websocket/impl/ping.ipp b/include/beast/websocket/impl/ping.ipp
index 905c9068..5083cb9e 100644
--- a/include/beast/websocket/impl/ping.ipp
+++ b/include/beast/websocket/impl/ping.ipp
@@ -139,8 +139,7 @@ operator()(error_code ec, bool again)
{
// suspend
d.state = 2;
- d.ws.ping_op_.template emplace<
- ping_op>(std::move(*this));
+ d.ws.ping_op_.emplace(std::move(*this));
return;
}
if(d.ws.failed_ || d.ws.wr_close_)
diff --git a/include/beast/websocket/impl/read.ipp b/include/beast/websocket/impl/read.ipp
index 02af9f24..1aab6931 100644
--- a/include/beast/websocket/impl/read.ipp
+++ b/include/beast/websocket/impl/read.ipp
@@ -456,8 +456,7 @@ operator()(error_code ec,
// suspend
d.state = do_pong_resume;
BOOST_ASSERT(d.ws.wr_block_ != &d);
- d.ws.rd_op_.template emplace<
- read_frame_op>(std::move(*this));
+ d.ws.rd_op_.emplace(std::move(*this));
return;
}
d.state = do_pong;
@@ -496,8 +495,7 @@ operator()(error_code ec,
{
// suspend
d.state = do_close_resume;
- d.ws.rd_op_.template emplace<
- read_frame_op>(std::move(*this));
+ d.ws.rd_op_.emplace(std::move(*this));
return;
}
d.state = do_close;
@@ -630,8 +628,7 @@ operator()(error_code ec,
{
// suspend
d.state = do_fail + 2;
- d.ws.rd_op_.template emplace<
- read_frame_op>(std::move(*this));
+ d.ws.rd_op_.emplace(std::move(*this));
return;
}
// fall through
diff --git a/include/beast/websocket/impl/write.ipp b/include/beast/websocket/impl/write.ipp
index 0f94fc66..2172eee8 100644
--- a/include/beast/websocket/impl/write.ipp
+++ b/include/beast/websocket/impl/write.ipp
@@ -491,8 +491,7 @@ operator()(error_code ec,
{
// suspend
d.state = do_maybe_suspend + 1;
- d.ws.wr_op_.template emplace<
- write_frame_op>(std::move(*this));
+ d.ws.wr_op_.emplace(std::move(*this));
return;
}
if(d.ws.failed_ || d.ws.wr_close_)