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).
131 Answer
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.