I am struggeling to understand why my quite simple UDP receiver is getting heap-free-after-use error (diagnosed by ASAN). The idea is listen to a configurable number of local ports for incoming packets.
I am here posting a simplified version of the 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);
}
}
According to ASAN m_endpoints.push_back(udp::endpoint(udp::v4(), port)) allocates some dynamic memory which is again freed by a later iteration. This eventually gives me use-after-free which messes up my application in a unpredictable way.
I cant really understand how the use of std::vector should not work in this case. Any ideas?
The documentation for async_receive_from
says: "Ownership of the sender_endpoint object is retained by the caller, which must guarantee that it is valid until the handler is called."
Your push_back
s may reallocate the underlying storage, leaving async_receive_from
with a dangling reference.
To avoid reallocation, reserve space for the necessary amount of elements before entering the loop:
m_endpoints.reserve(listen_ports.size());
m_sockets.reserve(listen_ports.size());