Fix the layout of bitfields (take 2)
Francois Gouget
fgouget at free.fr
Thu Aug 19 17:16:12 CDT 2004
Resubmitting as the previous patch was borked and did not apply.
> Changelog:
>
> * include/shlobj.h
> dlls/shell32/tests/generated.c
> tools/winapi/c_parser.pm
> tools/winapi/c_type.pm
> tools/winapi/winapi_test
>
> shlobj.h: Fix packing bug.
> shlobj.h: Fix the declaration of bitfields so their layout matches
> what MSVC generates.
> Modify winapi_test to compute the bitfields size/alignment like MSVC
> does.
> This moves the processing of the bitfields and arrays from
> winapi_test to to c_type.pm and adds a 'find_count' callback to deal
> with macros in the array size.
> winapi_test: Add support for unnamed 0 bit bitfields so we support
> the updated Wine headers.
> winapi_test: Add some support for DECLSPEC_ALIGN().
> winapi_test: Don't test the offset of bitfields since MSVC refuses to
> take their address.
> Update the impacted generated.c files.
Index: include/shlobj.h
===================================================================
RCS file: /var/cvs/wine/include/shlobj.h,v
retrieving revision 1.89
diff -u -r1.89 shlobj.h
--- include/shlobj.h 12 Aug 2004 03:33:30 -0000 1.89
+++ include/shlobj.h 18 Aug 2004 18:15:29 -0000
@@ -28,6 +28,7 @@
extern "C" {
#endif /* defined(__cplusplus) */
+/* Except for specific structs, this header is byte packed */
#include <pshpack1.h>
#include <shtypes.h>
@@ -210,6 +211,8 @@
*/
typedef INT (CALLBACK *BFFCALLBACK)(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
+#include <pshpack8.h>
+
typedef struct tagBROWSEINFOA {
HWND hwndOwner;
LPCITEMIDLIST pidlRoot;
@@ -236,6 +239,8 @@
#define PBROWSEINFO WINELIB_NAME_AW(PBROWSEINFO)
#define LPBROWSEINFO WINELIB_NAME_AW(LPBROWSEINFO)
+#include <poppack.h>
+
/* Browsing for directory. */
#define BIF_RETURNONLYFSDIRS 0x0001
#define BIF_DONTGOBELOWDOMAIN 0x0002
@@ -299,11 +304,15 @@
#define SHDID_COMPUTER_AUDIO 19
#define SHDID_COMPUTER_SHAREDDOCS 20
+#include <pshpack8.h>
+
typedef struct _SHDESCRIPTIONID
{ DWORD dwDescriptionId;
CLSID clsid;
} SHDESCRIPTIONID, *LPSHDESCRIPTIONID;
+#include <poppack.h>
+
HRESULT WINAPI SHGetDataFromIDListA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, int nFormat, LPVOID pv, int cb);
HRESULT WINAPI SHGetDataFromIDListW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, int nFormat, LPVOID pv, int cb);
#define SHGetDataFromIDList WINELIB_NAME_AW(SHGetDataFromIDList)
@@ -375,6 +348,7 @@
BOOL fShowSuperHidden : 1;
BOOL fNoNetCrawling : 1;
+ DWORD :0; /* Required for proper binary layout with gcc */
DWORD dwWin95Unused;
UINT uWin95Unused;
LONG lParamSort;
@@ -385,6 +359,7 @@
BOOL fStartPanelOn: 1;
BOOL fShowStartPage: 1;
UINT fSpareFlags : 13;
+ UINT :0; /* Required for proper binary layout with gcc */
} SHELLSTATE, *LPSHELLSTATE;
/**********************************************************************
@@ -408,6 +383,7 @@
BOOL fHideIcons : 1;
UINT fRestFlags : 3;
+ UINT :0; /* Required for proper binary layout with gcc */
} SHELLFLAGSTATE, * LPSHELLFLAGSTATE;
VOID WINAPI SHGetSettings(LPSHELLFLAGSTATE lpsfs, DWORD dwMask);
@@ -888,6 +864,7 @@
BOOL fDontPrettyNames:1;
BOOL fAdminsCreateCommonGroups:1;
UINT fUnusedFlags:7;
+ UINT :0; /* Required for proper binary layout with gcc */
UINT fMenuEnumFilter;
} CABINETSTATE, *LPCABINETSTATE;
@@ -901,8 +916,6 @@
*/
VOID WINAPI PathGetShortPath(LPWSTR pszPath);
-#include <poppack.h>
-
/****************************************************************************
* Drag And Drop Routines
*/
@@ -1017,6 +1030,8 @@
BOOL WINAPI ILIsParent(LPCITEMIDLIST,LPCITEMIDLIST,BOOL);
BOOL WINAPI ILRemoveLastID(LPITEMIDLIST);
+#include <poppack.h>
+
#ifdef __cplusplus
} /* extern "C" */
#endif /* defined(__cplusplus) */
Index: dlls/shell32/tests/generated.c
===================================================================
RCS file: /var/cvs/wine/dlls/shell32/tests/generated.c,v
retrieving revision 1.6
diff -u -r1.6 generated.c
--- dlls/shell32/tests/generated.c 16 Aug 2004 19:46:09 -0000 1.6
+++ dlls/shell32/tests/generated.c 19 Aug 2004 14:15:36 -0000
@@ -771,13 +758,13 @@
static void test_pack_AUTO_SCROLL_DATA(void)
{
- /* AUTO_SCROLL_DATA (pack 4) */
- TEST_TYPE(AUTO_SCROLL_DATA, 48, 4);
- TEST_FIELD(AUTO_SCROLL_DATA, int, iNextSample, 0, 4, 4);
- TEST_FIELD(AUTO_SCROLL_DATA, DWORD, dwLastScroll, 4, 4, 4);
- TEST_FIELD(AUTO_SCROLL_DATA, BOOL, bFull, 8, 4, 4);
- TEST_FIELD(AUTO_SCROLL_DATA, POINT[NUM_POINTS], pts, 12, 24, 4);
- TEST_FIELD(AUTO_SCROLL_DATA, DWORD[NUM_POINTS], dwTimes, 36, 12, 4);
+ /* AUTO_SCROLL_DATA (pack 1) */
+ TEST_TYPE(AUTO_SCROLL_DATA, 48, 1);
+ TEST_FIELD(AUTO_SCROLL_DATA, int, iNextSample, 0, 4, 1);
+ TEST_FIELD(AUTO_SCROLL_DATA, DWORD, dwLastScroll, 4, 4, 1);
+ TEST_FIELD(AUTO_SCROLL_DATA, BOOL, bFull, 8, 4, 1);
+ TEST_FIELD(AUTO_SCROLL_DATA, POINT[NUM_POINTS], pts, 12, 24, 1);
+ TEST_FIELD(AUTO_SCROLL_DATA, DWORD[NUM_POINTS], dwTimes, 36, 12, 1);
}
static void test_pack_BFFCALLBACK(void)
@@ -791,10 +814,10 @@
static void test_pack_CABINETSTATE(void)
{
/* CABINETSTATE (pack 1) */
- TEST_TYPE(CABINETSTATE, 10, 1);
+ TEST_TYPE(CABINETSTATE, 12, 1);
TEST_FIELD(CABINETSTATE, WORD, cLength, 0, 2, 1);
TEST_FIELD(CABINETSTATE, WORD, nVersion, 2, 2, 1);
- TEST_FIELD(CABINETSTATE, UINT, fMenuEnumFilter, 6, 4, 1);
+ TEST_FIELD(CABINETSTATE, UINT, fMenuEnumFilter, 8, 4, 1);
}
static void test_pack_CIDA(void)
@@ -889,7 +912,7 @@
{
/* LPCABINETSTATE */
TEST_TYPE(LPCABINETSTATE, 4, 4);
- TEST_TYPE_POINTER(LPCABINETSTATE, 10, 1);
+ TEST_TYPE_POINTER(LPCABINETSTATE, 12, 1);
}
static void test_pack_LPDROPFILES(void)
@@ -952,14 +975,14 @@
{
/* LPSHELLFLAGSTATE */
TEST_TYPE(LPSHELLFLAGSTATE, 4, 4);
- TEST_TYPE_POINTER(LPSHELLFLAGSTATE, 2, 1);
+ TEST_TYPE_POINTER(LPSHELLFLAGSTATE, 4, 1);
}
static void test_pack_LPSHELLSTATE(void)
{
/* LPSHELLSTATE */
TEST_TYPE(LPSHELLSTATE, 4, 4);
- TEST_TYPE_POINTER(LPSHELLSTATE, 29, 1);
+ TEST_TYPE_POINTER(LPSHELLSTATE, 32, 1);
}
static void test_pack_SHChangeDWORDAsIDList(void)
@@ -995,19 +1021,19 @@
static void test_pack_SHELLFLAGSTATE(void)
{
/* SHELLFLAGSTATE (pack 1) */
- TEST_TYPE(SHELLFLAGSTATE, 2, 1);
+ TEST_TYPE(SHELLFLAGSTATE, 4, 1);
}
static void test_pack_SHELLSTATE(void)
{
/* SHELLSTATE (pack 1) */
- TEST_TYPE(SHELLSTATE, 29, 1);
- TEST_FIELD(SHELLSTATE, DWORD, dwWin95Unused, 3, 4, 1);
- TEST_FIELD(SHELLSTATE, UINT, uWin95Unused, 7, 4, 1);
- TEST_FIELD(SHELLSTATE, LONG, lParamSort, 11, 4, 1);
- TEST_FIELD(SHELLSTATE, int, iSortDirection, 15, 4, 1);
- TEST_FIELD(SHELLSTATE, UINT, version, 19, 4, 1);
- TEST_FIELD(SHELLSTATE, UINT, uNotUsed, 23, 4, 1);
+ TEST_TYPE(SHELLSTATE, 32, 1);
+ TEST_FIELD(SHELLSTATE, DWORD, dwWin95Unused, 4, 4, 1);
+ TEST_FIELD(SHELLSTATE, UINT, uWin95Unused, 8, 4, 1);
+ TEST_FIELD(SHELLSTATE, LONG, lParamSort, 12, 4, 1);
+ TEST_FIELD(SHELLSTATE, int, iSortDirection, 16, 4, 1);
+ TEST_FIELD(SHELLSTATE, UINT, version, 20, 4, 1);
+ TEST_FIELD(SHELLSTATE, UINT, uNotUsed, 24, 4, 1);
}
static void test_pack_SHELLVIEWID(void)
Index: tools/winapi/c_parser.pm
===================================================================
RCS file: /var/cvs/wine/tools/winapi/c_parser.pm,v
retrieving revision 1.11
diff -u -r1.11 c_parser.pm
--- tools/winapi/c_parser.pm 12 Nov 2002 01:05:17 -0000 1.11
+++ tools/winapi/c_parser.pm 19 Aug 2004 12:03:48 -0000
@@ -1979,7 +1979,7 @@
}
$finished = 1;
- } elsif(s/^((?:enum\s+|struct\s+|union\s+)?\w+\b(?:\s*\*)*)\s*(\w+)\s*(\[.*?\]$|:\s*(\d+)$|\{)?//s) {
+ } elsif(s/^((?:enum\s+|struct\s+|union\s+)?\w+\b(?:\s+DECLSPEC_ALIGN\(.*?\)|\s*\*)*)\s*(\w+)\s*(\[.*?\]$|:\s*(\d+)$|\{)?//s) {
$type = "$sign$1";
$name = $2;
@@ -1998,6 +1998,12 @@
$type = $self->_format_c_type($type);
$finished = 1;
+ } elsif(s/^((?:enum\s+|struct\s+|union\s+)?\w+\b(?:\s*\*)*)\s*:\s*(\d+)$//s) {
+ $type = "$sign$1:$2";
+ $name = "";
+ $type = $self->_format_c_type($type);
+
+ $finished = 1;
} elsif(s/^((?:enum\s+|struct\s+|union\s+)?\w+\b(?:\s*\*)*\s*\((?:\s*CALLBACK|\s*NTAPI|\s*WINAPI)?(?:\s*\*)*)\s*(\w+)\s*(\)\s*\(.*?\))$//s) {
$type = $self->_format_c_type("$sign$1$3");
$name = $2;
Index: tools/winapi/c_type.pm
===================================================================
RCS file: /var/cvs/wine/tools/winapi/c_type.pm,v
retrieving revision 1.9
diff -u -r1.9 c_type.pm
--- tools/winapi/c_type.pm 4 May 2004 00:38:27 -0000 1.9
+++ tools/winapi/c_type.pm 19 Aug 2004 12:00:00 -0000
@@ -64,6 +64,17 @@
$$find_size = shift;
}
+########################################################################
+# set_find_count_callback
+#
+sub set_find_count_callback {
+ my $self = shift;
+
+ my $find_count = \${$self->{FIND_COUNT}};
+
+ $$find_count = shift;
+}
+
sub kind {
my $self = shift;
my $kind = \${$self->{KIND}};
@@ -236,6 +247,7 @@
my $find_align = \${$self->{FIND_ALIGN}};
my $find_kind = \${$self->{FIND_KIND}};
my $find_size = \${$self->{FIND_SIZE}};
+ my $find_count = \${$self->{FIND_COUNT}};
my $align = \${$self->{ALIGN}};
my $kind = \${$self->{KIND}};
@@ -251,70 +263,100 @@
my $max_field_align = 0;
my $offset = 0;
- my $offset_bits = 0;
+ my $bitfield_size = 0;
+ my $bitfield_bits = 0;
my $n = 0;
foreach my $field ($self->fields) {
my $type_name = $field->type_name;
- my $type_size = &$$find_size($type_name);
-
- my $base_type_name = $type_name;
- if ($base_type_name =~ s/^(.*?)\s*(?:\[\s*(.*?)\s*\]|:(\d+))?$/$1/) {
- my $count = $2;
- my $bits = $3;
- }
- my $base_size = &$$find_size($base_type_name);
- $$align = &$$find_align($base_type_name);
- if (defined($$align)) {
- $$align = $pack if $$align > $pack;
- $max_field_align = $$align if $$align > $max_field_align;
-
- if ($offset % $$align != 0) {
- $offset = (int($offset / $$align) + 1) * $$align;
- }
+ my $bits;
+ my $count;
+ if ($type_name =~ s/^(.*?)\s*(?:\[\s*(.*?)\s*\]|:(\d+))?$/$1/)
+ {
+ $count = $2;
+ $bits = $3;
}
-
- if ($$kind !~ /^(?:struct|union)$/) {
- $$kind = &$$find_kind($type_name) || "";
- }
-
- if (!defined($type_size)) {
- $$align = undef;
- $$size = undef;
- return;
- } elsif ($type_size >= 0) {
- if ($offset_bits) {
- $offset += $pack * int(($offset_bits + 8 * $pack - 1 ) / (8 * $pack));
- $offset_bits = 0;
- }
-
- $$$field_aligns[$n] = $$align;
- $$$field_base_sizes[$n] = $base_size;
- $$$field_offsets[$n] = $offset;
- $$$field_sizes[$n] = $type_size;
-
- $offset += $type_size;
- } else {
- $$$field_aligns[$n] = $$align;
- $$$field_base_sizes[$n] = $base_size;
- $$$field_offsets[$n] = $offset;
- $$$field_sizes[$n] = $type_size;
-
- $offset_bits += -$type_size;
- }
-
+ my $declspec_align;
+ if ($type_name =~ s/\s+DECLSPEC_ALIGN\((\d+)\)//)
+ {
+ $declspec_align=$1;
+ }
+ my $base_size = &$$find_size($type_name);
+ my $type_size=$base_size;
+ if (defined $count)
+ {
+ $count=&$$find_count($count) if ($count !~ /^\d+$/);
+ if (!defined $count)
+ {
+ $type_size=undef;
+ }
+ else
+ {
+ $type_size *= int($count);
+ }
+ }
+ if ($bitfield_size != 0)
+ {
+ if (($type_name eq "" and defined $bits and $bits == 0) or
+ (defined $type_size and $bitfield_size != $type_size) or
+ !defined $bits or
+ $bitfield_bits + $bits > 8 * $bitfield_size)
+ {
+ # This marks the end of the previous bitfield
+ $bitfield_size=0;
+ $bitfield_bits=0;
+ }
+ else
+ {
+ $bitfield_bits+=$bits;
+ $n++;
+ next;
+ }
+ }
+
+ $$align = &$$find_align($type_name);
+ $$align=$declspec_align if (defined $declspec_align);
+
+ if (defined $$align)
+ {
+ $$align = $pack if $$align > $pack;
+ $max_field_align = $$align if $$align > $max_field_align;
+
+ if ($offset % $$align != 0) {
+ $offset = (int($offset / $$align) + 1) * $$align;
+ }
+ }
+
+ if ($$kind !~ /^(?:struct|union)$/)
+ {
+ $$kind = &$$find_kind($type_name) || "";
+ }
+
+ if (!$type_size)
+ {
+ $$align = undef;
+ $$size = undef;
+ return;
+ }
+
+ $$$field_aligns[$n] = $$align;
+ $$$field_base_sizes[$n] = $base_size;
+ $$$field_offsets[$n] = $offset;
+ $$$field_sizes[$n] = $type_size;
+ $offset += $type_size;
+
+ if ($bits)
+ {
+ $bitfield_size=$type_size;
+ $bitfield_bits=$bits;
+ }
$n++;
}
$$align = $pack;
$$align = $max_field_align if $max_field_align < $pack;
- if ($offset_bits) {
- $offset += $pack * int(($offset_bits + 8 * $pack - 1 ) / (8 * $pack));
- $offset_bits = 0;
- }
-
$$size = $offset;
if ($$kind =~ /^(?:struct|union)$/) {
if ($$size % $$align != 0) {
Index: tools/winapi/winapi_test
===================================================================
RCS file: /var/cvs/wine/tools/winapi/winapi_test,v
retrieving revision 1.16
diff -u -r1.16 winapi_test
--- tools/winapi/winapi_test 16 Aug 2004 19:46:09 -0000 1.16
+++ tools/winapi/winapi_test 19 Aug 2004 12:07:50 -0000
@@ -177,13 +177,6 @@
local $_ = $type_name;
- my $count;
- my $bits;
- if (s/^(.*?)\s*(?:\[\s*(.*?)\s*\]|:(\d+))?$/$1/) {
- $count = $2;
- $bits = $3;
- }
-
my $align;
my $kind;
my $size;
@@ -313,21 +306,6 @@
$output->write("$type_name: type needn't be kludged\n");
}
- if (!defined($size)) {
- # $output->write("$type_name: can't find type\n");
- } elsif (defined($count)) {
- if ($count =~ /^\d+$/) {
- $size *= int($count);
- } elsif (defined(my $count2 = $defines{$count})) {
- $size *= int($count2);
- } else {
- $output->write("$type_name: can't parse type ('$_') ('$count')\n");
- $size = undef;
- }
- } elsif (defined($bits)) {
- $size = -$bits;
- }
-
return ($align, $kind, $size);
}
@@ -350,6 +328,11 @@
return $size;
}
+sub find_count {
+ my $count = shift;
+ return $defines{$count};
+}
+
foreach my $file (@files) {
$progress_current++;
@@ -426,6 +409,7 @@
$type->set_find_align_callback(\&find_align);
$type->set_find_kind_callback(\&find_kind);
$type->set_find_size_callback(\&find_size);
+ $type->set_find_count_callback(\&find_count);
my $pack = $packs[$#packs];
if (!defined($type->pack) && $type->kind =~ /^(?:struct|union)$/) {
@@ -728,6 +712,8 @@
my $field_align = $field->align;
next if $field_name eq "" || (defined($field_size) && $field_size < 0);
+ # We cannot take the address of a bitfield with MSVC
+ next if ($field_type_name =~ /:/);
if ($$optional_fields{$field_name}) {
# Nothing
--
Francois Gouget fgouget at free.fr http://fgouget.free.fr/
RFC 2549: ftp://ftp.isi.edu/in-notes/rfc2549.txt
IP over Avian Carriers with Quality of Service
More information about the wine-patches
mailing list