Stop using enums in bitfields

The C standard does not specify whether the underlying type of an enum
is signed or unsigned, and until C23 there was no way to control this
explicitly. GCC appears to make enums unsigned unless there is a
negative value among cases of the enum, in which case it becomes signed.
MSCV appears to make enums signed by default.

A bitfield of an enum type (which is not specificied in the C standard
either) behaves as if it was an instance of a numeric type with a
reduced value range. Specifically, a 'signed int val : 2;' bitfield will
have the possible values of -2, -1, 0, and 1, with the usual wraparound
behavior for the values that don't fit (although this too is
implementation-defined).

This causes the following issue, if we have:

typedef enum
{
  GTK_ZERO,
  GTK_ONE,
  GTK_TWO
} GtkFoo;

struct _GtkBar
{
  GtkFoo foo : 2;
};

and then assign bar.foo = GTK_TWO and read it back, it will have the
expected value of 2 (aka GTK_TWO) on GCC, but a value of -2 (not
matching any of the enum variants) on MSVC.

There does not seem to be any way to influence signedness of an enum
prior to C23, nor is there a 'unsigned GtkFoo foo : 2;' syntax. The only
remaining options seems to be never using enums in bitfields, which is
what this change implements.

In practice, this fixes GdkPipeIOStream crashing with an assertion when
trying to copy-paste in-app in MSVC builds on GTK.

Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>
This commit is contained in:
Sergey Bugaev 2023-10-09 17:53:21 +03:00
parent 28e51c763b
commit 964affb1cc
3 changed files with 3 additions and 3 deletions

View File

@ -40,7 +40,7 @@ struct _GdkIOPipe
GCond cond;
guchar *buffer;
gsize size;
GdkIOPipeState state : 2;
guint state : 2; /* GdkIOPipeState */
guint input_closed : 1;
guint output_closed : 1;
};

View File

@ -86,7 +86,7 @@ struct _GtkMenuTrackerItem
char *action_namespace;
char *action_and_target;
GMenuItem *item;
GtkMenuTrackerItemRole role : 4;
guint role : 4; /* GtkMenuTrackerItemRole */
guint is_separator : 1;
guint can_activate : 1;
guint sensitive : 1;

View File

@ -70,7 +70,7 @@ typedef struct {
CachedSizeX cached_size_x;
CachedSizeY cached_size_y;
GtkSizeRequestMode request_mode : 3;
guint request_mode : 3; /* GtkSizeRequestMode */
guint request_mode_valid : 1;
struct {
guint n_cached_requests : 15;