简单的 Boost UDP 接收器在使用 std::vector 时 gest heap-use-after-free
Simple Boost UDP receiver gest heap-use-after-free when using std::vector
我很难理解为什么我的非常简单的 UDP 接收器会出现使用后无堆错误(由 ASAN 诊断)。这个想法是监听传入数据包的可配置数量的本地端口。
我在这里发布的是class
的简化版
UdpReceiver.hpp
class UdpReceiver
{
public:
UdpReceiver(std::vector<int> listen_ports);
void run();
protected:
boost::asio::io_service m_io;
char m_receive_buffer[MAX_RECEIVE_LENGTH];
std::vector<udp::endpoint> m_endpoints;
std::vector<udp::socket> m_sockets;
void handleUdpData(const boost::system::error_code& error, size_t bytes_recvd, int idx);
};
UdpReceiver.cpp
UdpReceiver::UdpReceiver(std::vector<int> listen_ports) :
m_io()
{
int idx = 0;
try {
for (auto port: listen_ports) {
m_endpoints.push_back(udp::endpoint(udp::v4(), port));
m_sockets.push_back(udp::socket(m_io, m_endpoints[idx]));
m_sockets[idx].async_receive_from(
boost::asio::buffer(m_receive_buffer, MAX_RECEIVE_LENGTH), m_endpoints[idx],
boost::bind(&MessageParser::handleUdpData, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred,
idx)
);
idx++;
}
} catch(const std::exception &exc)
{
std::cerr <<exc.what();
exit(-1);
}
}
根据 ASAN m_endpoints.push_back(udp::endpoint(udp::v4(), port)) 分配一些动态内存,这些内存在稍后的迭代中再次释放。这最终让我实现了 use-after-free,它以一种不可预知的方式打乱了我的应用程序。
我真的无法理解为什么 std::vector 在这种情况下不起作用。有什么想法吗?
async_receive_from
的文档说:“sender_endpoint 对象的所有权由调用者保留,调用者必须保证它在调用处理程序之前有效。”
您的 push_back
可能会重新分配底层存储,留下 async_receive_from
悬空引用。
为避免重新分配,在进入循环之前保留 space 必要数量的元素:
m_endpoints.reserve(listen_ports.size());
m_sockets.reserve(listen_ports.size());
我很难理解为什么我的非常简单的 UDP 接收器会出现使用后无堆错误(由 ASAN 诊断)。这个想法是监听传入数据包的可配置数量的本地端口。
我在这里发布的是class
的简化版UdpReceiver.hpp
class UdpReceiver
{
public:
UdpReceiver(std::vector<int> listen_ports);
void run();
protected:
boost::asio::io_service m_io;
char m_receive_buffer[MAX_RECEIVE_LENGTH];
std::vector<udp::endpoint> m_endpoints;
std::vector<udp::socket> m_sockets;
void handleUdpData(const boost::system::error_code& error, size_t bytes_recvd, int idx);
};
UdpReceiver.cpp
UdpReceiver::UdpReceiver(std::vector<int> listen_ports) :
m_io()
{
int idx = 0;
try {
for (auto port: listen_ports) {
m_endpoints.push_back(udp::endpoint(udp::v4(), port));
m_sockets.push_back(udp::socket(m_io, m_endpoints[idx]));
m_sockets[idx].async_receive_from(
boost::asio::buffer(m_receive_buffer, MAX_RECEIVE_LENGTH), m_endpoints[idx],
boost::bind(&MessageParser::handleUdpData, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred,
idx)
);
idx++;
}
} catch(const std::exception &exc)
{
std::cerr <<exc.what();
exit(-1);
}
}
根据 ASAN m_endpoints.push_back(udp::endpoint(udp::v4(), port)) 分配一些动态内存,这些内存在稍后的迭代中再次释放。这最终让我实现了 use-after-free,它以一种不可预知的方式打乱了我的应用程序。
我真的无法理解为什么 std::vector 在这种情况下不起作用。有什么想法吗?
async_receive_from
的文档说:“sender_endpoint 对象的所有权由调用者保留,调用者必须保证它在调用处理程序之前有效。”
您的 push_back
可能会重新分配底层存储,留下 async_receive_from
悬空引用。
为避免重新分配,在进入循环之前保留 space 必要数量的元素:
m_endpoints.reserve(listen_ports.size());
m_sockets.reserve(listen_ports.size());