Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default structure alignment on i386 ("x86") is not compatible with System V ABI for Android #1079

Closed
BugsBeGone opened this issue Mar 30, 2019 · 4 comments

Comments

@BugsBeGone
Copy link
Contributor

BugsBeGone commented Mar 30, 2019

Currently using the latest release of JNA, 5.2.0 (some files in dist are actually 5.0.0).
Project files use jna-min.jar, and builds use libjnidispatch.so (from android-x86.jar).
JVM is whatever is included with Android Studio 3.3 for Linux.
Build machine is running Debian Stretch.
Note: I'm mainly focusing on Android , but this issue probably affects all Linux & Unix-like derivatives.
Currently using NDK revision 19c.

http://java-native-access.github.io/jna/5.2.0/javadoc/com/sun/jna/Structure.html#ALIGN_GNUC

The JavaDoc implies that all GNUC platforms will have a maximum structure
alignment of 4 bytes, but this is not so. Obviously x86_64 compatibility relies
on the maximum alignment being at least as big as an 8-byte pointer, but there
are no 32/64-bit checks. For i386, the maximum should always be 4 bytes,
assuming we are only covering the types mentioned here:
https://github.com/java-native-access/jna/blob/master/www/Mappings.md

For reference, here's the SysV ABI for i386:
"System V Application Binary Interface - Intel386™ Architecture Processor Supplement"
Fourth Edition. Section 3-2 "Fundamental Types", page 28:
http://www.sco.com/developers/devspecs/abi386-4.pdf

The following test source files both compile for me with no errors, but the
equivalent structures in Java (via the JNA) would result in unaligned access:
https://gist.github.com/BugsBeGone/8bf86685b532492f877a4ed5db7ce128

Those are C11 examples, but you can test with C++11 as well by changing the
includes from "<assert.h>" & "<stddef.h>", to "<type_traits>" & "<cstddef>".

There are workarounds for this issue on both the native and the Java side. The
most straightforward is to compile with "-malign-double", however this may cause
compatibility issues with other ABI-compliant binaries. I.e. if someone wants
to create a library to be accessed via JNA, but that also links against any
default-compiled prebuilt binaries, it may not work if the binaries have any
exported structs containing doubles.

The second option is to use "__attribute__((aligned(8))" on all double members
of all structs. This is ugly, and also requires a lot of messing around with
macros if your native code is targeting architectures other than i386. Even
better if the source is not yours, now you'll have another fork to maintain.

The third and final option is to override Structure.getNativeAlignment(). This
is probably the least invasive way to handle the issue, but means littering your
library mappings with overrides for each and every struct containing a double.
Also, it depends on various calls to the JNA Platform class, specifically the
methods isIntel() and is64Bit(). If the JNA project has any plans to refactor
some of those methods names in the future, it'll make for a pretty nasty
breaking change to anyone who needs this workaround:
https://github.com/java-native-access/jna/blob/master/TODO#L88

I'm working on a fix at the moment, just wanted to report this sooner rather
than later, in case anyone else is racking their brains trying to get stuff to
work for i386.

@matthiasblaesing
Copy link
Member

Could it be, that you are only seeing issues on Android?

# 32 Bit JDK
matthias@athena:~/src$ /usr/lib/jvm/java-11-openjdk-i386/bin/jrunscript -cp jnalib/build/jna.jar -e 'var f = com.sun.jna.Native.class.getDeclaredField("MAX_ALIGNMENT"); f.setAccessible(true); print(f.getInt(null))'
Warning: Nashorn engine is planned to be removed from a future JDK release
4
# 64 Bit JDK
matthias@athena:~/src$ /usr/lib/jvm/java-11-openjdk-amd64/bin/jrunscript -cp jnalib/build/jna.jar -e 'var f = com.sun.jna.Native.class.getDeclaredField("MAX_ALIGNMENT"); f.setAccessible(true); print(f.getInt(null))'
Warning: Nashorn engine is planned to be removed from a future JDK release
8

@BugsBeGone
Copy link
Contributor Author

BugsBeGone commented Mar 30, 2019

On Linux, MAX_ALIGNMENT will always be set to whatever the long size is, except for ARM, PPC & MIPS.
In other words, only for i386 & x64. For Android (and SPARC, AIX & MSVC) , it is always hard-coded to 8:
https://github.com/java-native-access/jna/blob/master/src/com/sun/jna/Native.java#L226

It doesn't matter though, because MAX_ALIGNMENT is ignored, except for OSX & PPC:
https://github.com/java-native-access/jna/blob/master/src/com/sun/jna/Structure.java#L1502
There is no catch for anything else under the "GNUC" family, so they will always align to whatever the size of the type is, calculated further up the method:
https://github.com/java-native-access/jna/blob/master/src/com/sun/jna/Structure.java#L1465

There is however, a catch for IBM AIX:
https://github.com/java-native-access/jna/blob/master/src/com/sun/jna/Structure.java#L1508
I don't know much about that architecture, but I assume it's almost the same issue.

Edit: okay, so I've been mentally switching a logical OR for a logical AND in my head this entire time.
MAX_ALIGNMENT is never ignored, EXCEPT for PowerPC special cases.

@BugsBeGone
Copy link
Contributor Author

BugsBeGone commented Mar 30, 2019

Essentially, I think the root of the issue is that this else block:
https://github.com/java-native-access/jna/blob/master/src/com/sun/jna/Structure.java#L1502
was always supposed to do something clever with the actual size and Native.MAX_ ALIGNMENT for all cases, not just for AIX and OSX on PPC. For whatever reason it was never added, maybe because the calculation for Native.MAX_ ALIGNMENT itself wasn't robust enough.

Edit: No longer relevant

@BugsBeGone BugsBeGone changed the title Default structure alignment on i386 ("x86") is not compatible with System V ABI Default structure alignment on i386 ("x86") is not compatible with System V ABI for Android Mar 30, 2019
BugsBeGone added a commit to BugsBeGone/jna that referenced this issue Mar 30, 2019
BugsBeGone added a commit to BugsBeGone/jna that referenced this issue Mar 30, 2019
@BugsBeGone
Copy link
Contributor Author

Probably need to update this test, but I'm not sure if any other platforms actually do result in a size of 28 bytes:
https://github.com/java-native-access/jna/blob/master/test/com/sun/jna/StructureTest.java#L185

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants