I noticed that cstruct mixes field packing rules, which makes it compute wrong offsets/sizes and disagree with C compilers about the layout of some structures.
Here is an example C program to use as a staring point:
#include <windows.h>
#include <stdio.h>
typedef struct _TEST {
__int32 Field32;
__int64 Field64;
} TEST;
int wmain(int argc, wchar_t\* argv[]) {
wprintf_s(L"End/size of Field32 = %zd\r\n", RTL_SIZEOF_THROUGH_FIELD(TEST, Field32));
wprintf_s(L"Start of Field64 = %d\r\n", FIELD_OFFSET(TEST, Field64));
wprintf_s(L"Total size of TEST = %zd\r\n", sizeof(TEST));
return 0;
}
It gives the following output:
End/size of Field32 = 4
Start of Field64 = 8
Total size of TEST = 16
As you can see, the compiler inserted a 4-byte padding before Field64 due to its natural alignment of 8 and adjusted the total size to 16 bytes,
Now here is a program that parses the same definition using the default settings in cstruct:
from dissect import cstruct
cparser = cstruct.cstruct()
cparser.load("""
struct TEST {
__int32 Field32;
__int64 Field64;
}
""")
print('End/size of', cparser.TEST.fields[0].name, '=', cparser.TEST.fields[0].type.size)
print('Start of', cparser.TEST.fields[1].name, '=', cparser.TEST.fields[1].offset)
print('Total size', cparser.TEST.size, 'with alignment', cparser.TEST.alignment)
It gives a different result:
End/size of Field32 = 4
Start of Field64 = 4
Total size 12 with alignment 8
As you can see, cstruct did not insert a 4-byte padding before Field64.
Loading the same definition with align=True yields the correct result:
End/size of Field32 = 4
Start of Field64 = 8
Total size 16 with alignment 8
If I understand it right, align=False is supposed to act similar to wrapping the definition in #include <pshpack1.h>/#include <poppack.h> and should trigger compact packing of fields that ignores their natural alignment. This is not, however, the default behavior for C. I think you should consider changing the defaults to use align=True to make sure that cstruct's defaults agree with C defaults.
Additionally, it might be useful to add support for different packing overrides, i.e., #include <pshpack1.h>, #include <pshpack2.h>, #include <pshpack4.h>, etc.
UPD: removed the wrong example which lead to wrong conclusions, sorry about that
I noticed that
cstructmixes field packing rules, which makes it compute wrong offsets/sizes and disagree with C compilers about the layout of some structures.Here is an example C program to use as a staring point:
It gives the following output:
As you can see, the compiler inserted a 4-byte padding before
Field64due to its natural alignment of 8 and adjusted the total size to 16 bytes,Now here is a program that parses the same definition using the default settings in
cstruct:It gives a different result:
As you can see,
cstructdid not insert a 4-byte padding beforeField64.Loading the same definition with
align=Trueyields the correct result:If I understand it right,
align=Falseis supposed to act similar to wrapping the definition in#include <pshpack1.h>/#include <poppack.h>and should trigger compact packing of fields that ignores their natural alignment. This is not, however, the default behavior for C. I think you should consider changing the defaults to usealign=Trueto make sure thatcstruct's defaults agree with C defaults.Additionally, it might be useful to add support for different packing overrides, i.e.,
#include <pshpack1.h>,#include <pshpack2.h>,#include <pshpack4.h>, etc.UPD: removed the wrong example which lead to wrong conclusions, sorry about that