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

Fix alignment and size for nested types #147

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
129 changes: 129 additions & 0 deletions libtest/StructNestedTest.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#include <stdio.h>
#include <stddef.h>
#include <string.h>

typedef struct _A {
int x;
char y;
} A;

typedef struct _B {
char x;
int y;
} B;

typedef struct _C {
char x;
char y;
int z;
} C;

typedef struct _D {
char x;
long long y;
int z;
} D;

typedef struct _E {
char x;
D y;
} E;

typedef struct _Array1 {
D t[3];
} Array1;

typedef union _MyLargeInteger {

struct {
unsigned int LowPart;
int HighPart;
} u;
long long QuadPart;
} MyLargeInteger;

typedef struct _F {
int x;
MyLargeInteger y;
} F;

typedef struct _G {
char x;
MyLargeInteger y;
int z;
} G;

typedef struct _Array2 {
G t[3];
} Array2;

typedef union _Union1 {
int intVal[2];
char ch[8];
MyLargeInteger my;
short ss[4];
long long u;
} Union1;

typedef struct _H {
char x[3];
} H;

typedef union _Union2 {
H x[5];
} Union2;

typedef struct _J {
short x;
char y[3];
} J;

typedef union _Union3 {
J x[5];
char y[13];
} Union3;

struct Result {
int align;
int size;
};

#define DUMP(type) \
do { \
typedef struct _AlignType##type { \
char c; \
type d; \
} AlignType##type; \
if(strcmp(#type,name)==0){ \
res.align = offsetof(AlignType##type, d); \
res.size = sizeof(type); \
} \
} while(0)

static struct Result getTypeDescription(const char * name) {
struct Result res = {0, 0};
DUMP(A);
DUMP(B);
DUMP(C);
DUMP(D);
DUMP(E);
DUMP(Array1);
DUMP(MyLargeInteger);
DUMP(F);
DUMP(G);
DUMP(Array2);
DUMP(Union1);
DUMP(H);
DUMP(Union2);
DUMP(J);
DUMP(Union3);
return res;
}

int getTypeSize(const char * name) {
return getTypeDescription(name).size;
}

int getTypeAlign(const char * name) {
return getTypeDescription(name).align;
}
27 changes: 21 additions & 6 deletions src/main/java/jnr/ffi/Struct.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ static final class Info {
int size = 0;
int minAlign = 1;
boolean isUnion = false;
boolean resetIndex = false;
int currentSize = -1; // only used when this is an enum and add array elements

Alignment alignment = new Alignment(0);

Expand Down Expand Up @@ -93,6 +93,20 @@ private jnr.ffi.Pointer allocateMemory(int flags) {
}
}

private int nextOffset(int size, int alignment) {
if (isUnion) {
if (currentSize > -1) { // add element to an array
int result = align(this.currentSize, alignment);
this.currentSize = result + size;
return result;
} else {
return 0;
}
} else {
return align(this.size, alignment);
}
}

public final void useMemory(jnr.ffi.Pointer io) {
this.memory = io;
}
Expand All @@ -105,7 +119,7 @@ protected final int addField(int sizeBits, int alignBits, Offset offset) {

protected final int addField(int sizeBits, int alignBits) {
final int alignment = this.alignment.intValue() > 0 ? Math.min(this.alignment.intValue(), (alignBits >> 3)) : (alignBits >> 3);
final int offset = resetIndex ? 0 : align(this.size, alignment);
final int offset = nextOffset(sizeBits >> 3, alignment);
this.size = Math.max(this.size, offset + (sizeBits >> 3));
this.minAlign = Math.max(this.minAlign, alignment);
return offset;
Expand Down Expand Up @@ -139,7 +153,7 @@ protected Struct(Runtime runtime, Struct enclosing) {
*/
protected Struct(Runtime runtime, final boolean isUnion) {
this(runtime);
__info.resetIndex = isUnion;
__info.currentSize = -1;
__info.isUnion = isUnion;
}

Expand Down Expand Up @@ -314,14 +328,14 @@ protected abstract class Member {
* Starts an array construction session
*/
protected final void arrayBegin() {
__info.resetIndex = false;
__info.currentSize = 0;
}

/**
* Ends an array construction session
*/
protected final void arrayEnd() {
__info.resetIndex = __info.isUnion;
__info.currentSize = -1;
}

/**
Expand Down Expand Up @@ -684,10 +698,11 @@ protected UTF8String[] array(UTF8String[] array, int stringLength) {

protected final <T extends Struct> T inner(T struct) {
int alignment = __info.alignment.intValue() > 0 ? Math.min(__info.alignment.intValue(), struct.__info.getMinimumAlignment()) : struct.__info.getMinimumAlignment();
int offset = __info.resetIndex ? 0 : align(__info.size, alignment);
int offset = __info.nextOffset(struct.__info.size, alignment);
struct.__info.enclosing = this;
struct.__info.offset = offset;
__info.size = Math.max(__info.size, offset + struct.__info.size);
__info.minAlign = Math.max(__info.minAlign, alignment);
return struct;
}

Expand Down
23 changes: 18 additions & 5 deletions src/main/java/jnr/ffi/StructLayout.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class StructLayout extends Type {

private final Runtime runtime;
private final boolean isUnion = false;
private boolean resetIndex = false;
private int currentSize = -1; // only used when this is an enum and add array elements
StructLayout enclosing = null;
int offset = 0;
int size = 0;
Expand Down Expand Up @@ -100,9 +100,22 @@ private static int align(int offset, int alignment) {
return (offset + alignment - 1) & ~(alignment - 1);
}

private int nextOffset(int size, int alignment) {
if (isUnion) {
if (currentSize > -1) { // add element to an array
int result = align(this.currentSize, alignment);
this.currentSize = result + size;
return result;
} else {
return 0;
}
} else {
return align(this.size, alignment);
}
}

protected final int addField(int size, int align) {
final int off = resetIndex ? 0 : align(this.size, align);
final int off = nextOffset(size, align);
this.size = Math.max(this.size, off + size);
this.alignment = Math.max(this.alignment, align);
this.paddedSize = align(this.size, this.alignment);
Expand Down Expand Up @@ -162,14 +175,14 @@ public final long offset() {
* Starts an array construction session
*/
protected final void arrayBegin() {
resetIndex = false;
this.currentSize = 0;
}

/**
* Ends an array construction session
*/
protected final void arrayEnd() {
resetIndex = isUnion;
this.currentSize = -1;
}

/**
Expand Down Expand Up @@ -201,7 +214,7 @@ protected final <T extends StructLayout> T inner(T structLayout) {
structLayout.offset = align(this.size, structLayout.alignment);
this.size = structLayout.offset + structLayout.size;
this.paddedSize = align(this.size, this.alignment());

this.alignment = Math.max(this.alignment, structLayout.alignment);
return structLayout;
}

Expand Down