Skip to content

Structure layout disagreeing with C compilers #63

Description

@diversenok

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions