From 7c41a6529bd7cb6a6c1f9982bb0d7fb8da5f9fc0 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 15 May 2024 12:50:51 +0100 Subject: [PATCH 1/4] girparser: Use INTEGER_ALIAS to reduce repetition As a special case, keep the historical behaviour of treating gchar as being signed, both on platforms where it is genuinely signed (for example x86 Linux) and where it is unsigned (for example ARM, s390x and PowerPC Linux). Changing gchar to use INTEGER_ALIAS would have a regression risk, so if we want to do that, it should be as a separate change. No functional change intended. Signed-off-by: Simon McVittie --- girepository/girparser.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/girepository/girparser.c b/girepository/girparser.c index a469d3dd2..1ec22213d 100644 --- a/girepository/girparser.c +++ b/girepository/girparser.c @@ -462,19 +462,23 @@ G_STATIC_ASSERT (signedness (int) == 1); G_STATIC_ASSERT (signedness (unsigned int) == 0); static IntegerAliasInfo integer_aliases[] = { - { "gchar", sizeof (gchar), 1 }, - { "guchar", sizeof (guchar), 0 }, - { "gshort", sizeof (gshort), 1 }, - { "gushort", sizeof (gushort), 0 }, - { "gint", sizeof (gint), 1 }, - { "guint", sizeof (guint), 0 }, - { "glong", sizeof (glong), 1 }, - { "gulong", sizeof (gulong), 0 }, - { "gssize", sizeof (gssize), 1 }, - { "gsize", sizeof (gsize), 0 }, - { "gintptr", sizeof (gintptr), 1 }, - { "guintptr", sizeof (guintptr), 0 }, + /* It is platform-dependent whether gchar is signed or unsigned, but + * GObject-Introspection has traditionally treated it as signed, + * so continue to hard-code that instead of using INTEGER_ALIAS */ + { "gchar", sizeof (gchar), 1 }, + #define INTEGER_ALIAS(T) { #T, sizeof (T), signedness (T) } + INTEGER_ALIAS (guchar), + INTEGER_ALIAS (gshort), + INTEGER_ALIAS (gushort), + INTEGER_ALIAS (gint), + INTEGER_ALIAS (guint), + INTEGER_ALIAS (glong), + INTEGER_ALIAS (gulong), + INTEGER_ALIAS (gssize), + INTEGER_ALIAS (gsize), + INTEGER_ALIAS (gintptr), + INTEGER_ALIAS (guintptr), INTEGER_ALIAS (off_t), INTEGER_ALIAS (time_t), #ifdef G_OS_UNIX From a0ed94a11d457037c6dc4572fc1cdea492623cdc Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 15 May 2024 12:51:48 +0100 Subject: [PATCH 2/4] Provide private G_SIGNEDNESS_OF macro in glib-private.h Signed-off-by: Simon McVittie --- girepository/girparser.c | 13 ++----------- glib/glib-init.c | 5 +++++ glib/glib-private.h | 10 ++++++++++ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/girepository/girparser.c b/girepository/girparser.c index 1ec22213d..dd0fb48b2 100644 --- a/girepository/girparser.c +++ b/girepository/girparser.c @@ -28,6 +28,7 @@ #include "girnode-private.h" #include "gitypelib-internal.h" +#include "glib-private.h" #include #include @@ -451,23 +452,13 @@ typedef struct { unsigned int is_signed : 1; } IntegerAliasInfo; -/* - * signedness: - * @T: a numeric type - * - * Returns: 1 if @T is signed, 0 if it is unsigned - */ -#define signedness(T) (((T) -1) <= 0) -G_STATIC_ASSERT (signedness (int) == 1); -G_STATIC_ASSERT (signedness (unsigned int) == 0); - static IntegerAliasInfo integer_aliases[] = { /* It is platform-dependent whether gchar is signed or unsigned, but * GObject-Introspection has traditionally treated it as signed, * so continue to hard-code that instead of using INTEGER_ALIAS */ { "gchar", sizeof (gchar), 1 }, -#define INTEGER_ALIAS(T) { #T, sizeof (T), signedness (T) } +#define INTEGER_ALIAS(T) { #T, sizeof (T), G_SIGNEDNESS_OF (T) } INTEGER_ALIAS (guchar), INTEGER_ALIAS (gshort), INTEGER_ALIAS (gushort), diff --git a/glib/glib-init.c b/glib/glib-init.c index 7d4a4d5d9..8e2957aaf 100644 --- a/glib/glib-init.c +++ b/glib/glib-init.c @@ -22,6 +22,7 @@ #include "config.h" #include "glib-init.h" +#include "glib-private.h" #include "gmacros.h" #include "gtypes.h" #include "gutils.h" /* for GDebugKey */ @@ -42,6 +43,10 @@ /* This seems as good a place as any to make static assertions about platform * assumptions we make throughout GLib. */ +/* Test that private macro G_SIGNEDNESS_OF() works as intended */ +G_STATIC_ASSERT (G_SIGNEDNESS_OF (int) == 1); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (unsigned int) == 0); + /* We do not support 36-bit bytes or other historical curiosities. */ G_STATIC_ASSERT (CHAR_BIT == 8); diff --git a/glib/glib-private.h b/glib/glib-private.h index c24b59d6f..7ab2579b0 100644 --- a/glib/glib-private.h +++ b/glib/glib-private.h @@ -25,6 +25,16 @@ #include "gstdioprivate.h" #include "gdatasetprivate.h" +/* + * G_SIGNEDNESS_OF: + * @T: a numeric type such as `unsigned int` + * + * An integer constant expression indicating whether @T is a signed type. + * + * Returns: 1 if @T is signed, 0 if it is unsigned + */ +#define G_SIGNEDNESS_OF(T) (((T) -1) <= 0) + /* gcc defines __SANITIZE_ADDRESS__, clang sets the address_sanitizer * feature flag. * From 7efb96d29b014dbd5a160967c31f8c791cc9f8ca Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 15 May 2024 12:56:54 +0100 Subject: [PATCH 3/4] glib-init: Statically assert that types have appropriate signedness Some of these are properties of a Standard C or POSIX platform that are true by definition and checked for completeness (for example intptr_t is defined to be signed, and uintptr_t unsigned), while others are checking that GLib's type detection has been done correctly. Signed-off-by: Simon McVittie --- glib/glib-init.c | 36 ++++++++++++++++++++++++++++++++++++ glib/glib-unix.c | 3 +++ 2 files changed, 39 insertions(+) diff --git a/glib/glib-init.c b/glib/glib-init.c index 8e2957aaf..969570aa6 100644 --- a/glib/glib-init.c +++ b/glib/glib-init.c @@ -82,6 +82,11 @@ G_STATIC_ASSERT (G_ALIGNOF (TestInt) == G_ALIGNOF (int)); G_STATIC_ASSERT (sizeof (gchar) == 1); G_STATIC_ASSERT (sizeof (guchar) == 1); + +/* It is platform-dependent whether gchar is signed or unsigned, so there + * is no assertion here for it */ +G_STATIC_ASSERT (G_SIGNEDNESS_OF (guchar) == 0); + G_STATIC_ASSERT (sizeof (gint8) * CHAR_BIT == 8); G_STATIC_ASSERT (sizeof (guint8) * CHAR_BIT == 8); G_STATIC_ASSERT (sizeof (gint16) * CHAR_BIT == 16); @@ -100,12 +105,16 @@ G_STATIC_ASSERT (G_MINSHORT == SHRT_MIN); G_STATIC_ASSERT (G_MAXSHORT == SHRT_MAX); G_STATIC_ASSERT (sizeof (unsigned short) == sizeof (gushort)); G_STATIC_ASSERT (G_MAXUSHORT == USHRT_MAX); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (gshort) == 1); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (gushort) == 0); G_STATIC_ASSERT (sizeof (int) == sizeof (gint)); G_STATIC_ASSERT (G_MININT == INT_MIN); G_STATIC_ASSERT (G_MAXINT == INT_MAX); G_STATIC_ASSERT (sizeof (unsigned int) == sizeof (guint)); G_STATIC_ASSERT (G_MAXUINT == UINT_MAX); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (gint) == 1); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (guint) == 0); G_STATIC_ASSERT (sizeof (long) == GLIB_SIZEOF_LONG); G_STATIC_ASSERT (sizeof (long) == sizeof (glong)); @@ -113,6 +122,8 @@ G_STATIC_ASSERT (G_MINLONG == LONG_MIN); G_STATIC_ASSERT (G_MAXLONG == LONG_MAX); G_STATIC_ASSERT (sizeof (unsigned long) == sizeof (gulong)); G_STATIC_ASSERT (G_MAXULONG == ULONG_MAX); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (glong) == 1); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (gulong) == 0); G_STATIC_ASSERT (G_HAVE_GINT64 == 1); @@ -132,6 +143,10 @@ G_STATIC_ASSERT (G_ALIGNOF (gssize) == G_ALIGNOF (size_t)); * However, we do not assume that GPOINTER_TO_SIZE can store an arbitrary * pointer in a gsize (known to be false on CHERI). */ G_STATIC_ASSERT (sizeof (size_t) <= sizeof (void *)); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (size_t) == 0); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (gsize) == 0); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (gssize) == 1); + /* Standard C does not guarantee that size_t is the same as uintptr_t, * but GLib currently assumes they are the same: see * . @@ -144,10 +159,13 @@ G_STATIC_ASSERT (sizeof (size_t) <= sizeof (void *)); G_STATIC_ASSERT (sizeof (size_t) == sizeof (uintptr_t)); G_STATIC_ASSERT (G_ALIGNOF (size_t) == G_ALIGNOF (uintptr_t)); #endif + /* goffset is always 64-bit, even if off_t is only 32-bit * (compiling without large-file-support on 32-bit) */ G_STATIC_ASSERT (sizeof (goffset) == sizeof (gint64)); G_STATIC_ASSERT (G_ALIGNOF (goffset) == G_ALIGNOF (gint64)); +/* goffset is always signed */ +G_STATIC_ASSERT (G_SIGNEDNESS_OF (goffset) == 1); G_STATIC_ASSERT (sizeof (gfloat) == sizeof (float)); G_STATIC_ASSERT (G_ALIGNOF (gfloat) == G_ALIGNOF (float)); @@ -158,26 +176,44 @@ G_STATIC_ASSERT (sizeof (gintptr) == sizeof (intptr_t)); G_STATIC_ASSERT (sizeof (guintptr) == sizeof (uintptr_t)); G_STATIC_ASSERT (G_ALIGNOF (gintptr) == G_ALIGNOF (intptr_t)); G_STATIC_ASSERT (G_ALIGNOF (guintptr) == G_ALIGNOF (uintptr_t)); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (gintptr) == 1); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (guintptr) == 0); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (intptr_t) == 1); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (uintptr_t) == 0); G_STATIC_ASSERT (sizeof (gint8) == sizeof (int8_t)); G_STATIC_ASSERT (sizeof (guint8) == sizeof (uint8_t)); G_STATIC_ASSERT (G_ALIGNOF (gint8) == G_ALIGNOF (int8_t)); G_STATIC_ASSERT (G_ALIGNOF (guint8) == G_ALIGNOF (uint8_t)); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (gint8) == 1); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (guint8) == 0); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (int8_t) == 1); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (uint8_t) == 0); G_STATIC_ASSERT (sizeof (gint16) == sizeof (int16_t)); G_STATIC_ASSERT (sizeof (guint16) == sizeof (uint16_t)); G_STATIC_ASSERT (G_ALIGNOF (gint16) == G_ALIGNOF (int16_t)); G_STATIC_ASSERT (G_ALIGNOF (guint16) == G_ALIGNOF (uint16_t)); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (int16_t) == 1); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (uint16_t) == 0); G_STATIC_ASSERT (sizeof (gint32) == sizeof (int32_t)); G_STATIC_ASSERT (sizeof (guint32) == sizeof (uint32_t)); G_STATIC_ASSERT (G_ALIGNOF (gint32) == G_ALIGNOF (int32_t)); G_STATIC_ASSERT (G_ALIGNOF (guint32) == G_ALIGNOF (uint32_t)); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (gint32) == 1); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (guint32) == 0); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (int32_t) == 1); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (uint32_t) == 0); G_STATIC_ASSERT (sizeof (gint64) == sizeof (int64_t)); G_STATIC_ASSERT (sizeof (guint64) == sizeof (uint64_t)); G_STATIC_ASSERT (G_ALIGNOF (gint64) == G_ALIGNOF (int64_t)); G_STATIC_ASSERT (G_ALIGNOF (guint64) == G_ALIGNOF (uint64_t)); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (gint64) == 1); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (guint64) == 0); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (int64_t) == 1); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (uint64_t) == 0); /** * g_mem_gc_friendly: diff --git a/glib/glib-unix.c b/glib/glib-unix.c index 7cb76dd33..932c230d6 100644 --- a/glib/glib-unix.c +++ b/glib/glib-unix.c @@ -38,6 +38,7 @@ #include "config.h" +#include "glib-private.h" #include "glib-unix.h" #include "glib-unixprivate.h" #include "gmain-internal.h" @@ -66,9 +67,11 @@ G_STATIC_ASSERT (sizeof (ssize_t) == GLIB_SIZEOF_SSIZE_T); G_STATIC_ASSERT (G_ALIGNOF (gssize) == G_ALIGNOF (ssize_t)); +G_STATIC_ASSERT (G_SIGNEDNESS_OF (ssize_t) == 1); G_STATIC_ASSERT (sizeof (GPid) == sizeof (pid_t)); G_STATIC_ASSERT (G_ALIGNOF (GPid) == G_ALIGNOF (pid_t)); +/* It's platform-dependent whether pid_t is signed, so no assertion */ /* If this assertion fails, then the ABI of g_unix_open_pipe() would be * ambiguous on this platform. From c2e7b2f3b0ade7b90f2957ad9b8c4e85b6485f72 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Tue, 4 Jun 2024 17:09:40 +0100 Subject: [PATCH 4/4] girepository: Fix type of precondition return values This fixes a compiler warning (`-Wnon-literal-null-conversion`) on clang 13 on macOS. Signed-off-by: Philip Withnall --- girepository/girepository.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/girepository/girepository.c b/girepository/girepository.c index c768af18f..a6a81716d 100644 --- a/girepository/girepository.c +++ b/girepository/girepository.c @@ -657,11 +657,11 @@ register_internal (GIRepository *repository, Header *header; const char *namespace; - g_return_val_if_fail (typelib != NULL, FALSE); + g_return_val_if_fail (typelib != NULL, NULL); header = (Header *)typelib->data; - g_return_val_if_fail (header != NULL, FALSE); + g_return_val_if_fail (header != NULL, NULL); namespace = gi_typelib_get_string (typelib, header->namespace); @@ -1907,7 +1907,7 @@ require_internal (GIRepository *repository, char *tmp_version = NULL; g_return_val_if_fail (GI_IS_REPOSITORY (repository), NULL); - g_return_val_if_fail (namespace != NULL, FALSE); + g_return_val_if_fail (namespace != NULL, NULL); typelib = get_registered_status (repository, namespace, version, allow_lazy, &is_lazy, &version_conflict);