brettwooldridge / NuProcess

Low-overhead, non-blocking I/O, external Process implementation for Java

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

EpollEvent memory alignment is incorrect

bturner opened this issue · comments

Foremost: This misalignment doesn't matter with the current code, and, further, it may not actually be misaligned on all platforms. But on Linux Mint 18 (Ubuntu 16.04) x86_64, it is misaligned.

Environment:

bturner@elysoun ~$ uname -a
Linux elysoun 4.10.0-38-generic #42~16.04.1-Ubuntu SMP Tue Oct 10 16:32:20 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
bturner@elysoun ~$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 5.4.0-6ubuntu1~16.04.5' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.5)

It's quite simple to verify the misalignment. Here's a simple C program:

#include <sys/epoll.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
    printf("sizeof(epoll_event): %lu\n", sizeof(struct epoll_event));

    return 0;
}

The result: 12. Calling new EpollEvent().size(), meanwhile, in the NuProcess code, returns 16. Using ALIGN_GNUC is adding 4 bytes of padding to the end of the structure.

Since nothing in the NuProcess code tries to marshal multiple EpollEvent structs in a single call the misalignment is benign, just a tiny overallocation in memory. But if you ever wanted to, say, update ProcessEpoll to pass a higher max than 1, with the current memory alignment setting it fails--EpollEvents beyond the first one appear uninitialized after the call returns >1.

Setting the alignment to ALIGN_NONE fixes this issue, at least for x86_64, and results in the correct size of 12.

On my system, the bits/epoll.h (/usr/include/x86_64-linux-gnu/bits/epoll.h) header has the following define:

#define __EPOLL_PACKED __attribute__ ((__packed__))

That's included by sys/epoll.h, which then has the following structure definition:

struct epoll_event
{
  uint32_t events;      /* Epoll events */
  epoll_data_t data;    /* User data variable */
} __EPOLL_PACKED;

__attribute__ ((__packed__)) disables inserting padding memory alignment, per GCC's documentation:

packed
This attribute, attached to struct or union type definition, specifies that each member (other than zero-width bit-fields) of the structure or union is placed to minimize the memory required. When attached to an enum definition, it indicates that the smallest integral type should be used. (GCC 7.2, but similar for earlier versions.)

This was fixed when #80 was merged