I observe the below error when receiving UDP packets via Epoll:
'unaligned tcache chunk detected'
I've managed to locate which part of the code but it doesn't make much sense.
This is the original code:
while (_listen)
{
const int count = epoll_wait(_epollFd, &events[0], MAX_SOCKETS, -1);
assert(count != -1);
for (int j = 0; j < count; j)
{
iovec iov;
char control[1024];
msghdr msg;
iov.iov_base = _buffer;
iov.iov_len = sizeof(_buffer);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_namelen = sizeof(sockaddr_in);
msg.msg_control = &control[0];
msg.msg_controllen = 1024;
const int sock = events[j].data.fd;
const int64_t n = recvmsg(sock, &msg, 0); // This line seems to cause the problem
// More code
}
}
_buffer
is a class member declared as: char _buffer[65'536];
By trial and error I narrowed the problem to this line:
const int64_t n = recvmsg(sock, &msg, 0);
So I replaced ::recvmsg()
with a call to ::recv()
and it runs successfully:
while (_listen)
{
const int count = epoll_wait(_epollFd, &events[0], MAX_SOCKETS, -1);
assert(count != -1);
for (int j = 0; j < count; j)
{
const int sock = events[j].data.fd;
const int64_t n = recv(sock, _buffer, sizeof(_buffer), 0);
// More code
}
}
Now the problem doesn't occur. What is causing this?
I'd like to understand why the first code doesn't work. The only memory is _buffer
and that's not manually allocated.
(Unfortunately I cannot use a sanitize build due to the environment/build system).
CodePudding user response:
In your code you forgot to set member msg_name
of the struct msg
:
iovec iov;
char control[1024];
msghdr msg;
// add the following line:
sockaddr_in addr;
iov.iov_base = _buffer;
iov.iov_len = sizeof(_buffer);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = &control[0];
msg.msg_controllen = 1024;
// set the following members:
msg.msg_name = &addr;
msg.msg_namelen = sizeof(addr);
const int sock = events[j].data.fd;
const int64_t n = recvmsg(sock, &msg, 0);
// More code
The reason you had memory corruption is because you had undefined behavior: recvmsg()
tried to write to pointer msg.msg_name
, but the latter contained an uninitialized memory address, so recvmsg()
was actually writing to an invalid location.
recvmsg()
writes information about the host that sent the message inside msg.msg_name
.