Search code examples
clinuxservervalgrindepoll

epoll_event different initialization causes different epoll_wait results


Running the following snippet with valgrind:

struct epoll_event server_socket_conn_ev = {.events = EPOLLIN, .data.fd = server_socket};
//server_socket_conn_ev.data.ptr = NULL;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_socket, &server_socket_conn_ev) == -1) {
    perror(NULL);
    return 1;
}

struct epoll_event new_event;

while(1) {
    epoll_wait(epoll_fd, &new_event, 1, -1);
  ...

I get the following error:

==16219== Syscall param epoll_ctl(event) points to uninitialised byte(s)
==16219==    at 0x524AA7A: epoll_ctl (syscall-template.S:84)
==16219==    by 0x401464: run_server (server.c:85)
==16219==    by 0x401367: main (server.c:57)
==16219==  Address 0xfff0002e8 is on thread 1's stack
==16219==  in frame #1, created by run_server (server.c:69)

The fix here, is to uncomment the second line from the snippet. However, doing so gives me different results, specifically the variable new_event.

If do not not initialize data.ptr to NULL, then I got the following value for new_event:

(gdb) p new_event
$1 = {events = 1, data = {ptr = 0x3, fd = 3, u32 = 3, u64 = 3}}

as expected.

However, by initializing data.ptr = NULL, then new_event remains initialized after the wait call:

(gdb) p new_event
$1 = {events = 1, data = {ptr = 0x0, fd = 0, u32 = 0, u64 = 0}}

1.) Why does this initialization affect the result of epoll_wait?

2.) How can I get rid of the valgrind error and get the results I expect?


Solution

    1. new_event.data is a union. That is to say, its various elements share the same storage. When you initialise data.ptr to NULL, that overwrites some (potentially all) the other fields (depending on your system, specifically what size pointers are).
    2. Two options come to mind:
    • (a) Configure valgrind to suppress the error, as it's arguably a false positive (valgrind doesn't know that it's OK to have some parts of that struct uninitialised)
    • (b) Initialise the struct in a slightly longer-winded way:

    struct epoll_event server_socket_conn_ev = {.events = EPOLLIN, .ptr = NULL }; server_socket_conn_ev.fd = server_socket;