girnode: Fix computation of union member offsets

Regression from 501ff95c. Union member offsets are always 0, but we need
to mark them as 'COMPUTED' otherwise they are not written to the
typelib, which results in gi_field_info_get_offset() returning 0xffff.

Since gi_field_info_get/set_field() cannot check that the offset is
within the size of the struct or union, that means poking into invalid
memory addresses.

This also adds some basic tests for GIFieldInfo which would have caught
this bug.

Closes: #3745
This commit is contained in:
Philip Chimento
2025-09-29 10:50:25 -07:00
parent e5de125a09
commit d632c3ab3d
3 changed files with 173 additions and 0 deletions

View File

@@ -465,6 +465,8 @@ compute_union_field_offsets (GIIrTypelibBuild *build,
{ {
size = MAX (size, member_size); size = MAX (size, member_size);
alignment = MAX (alignment, member_alignment); alignment = MAX (alignment, member_alignment);
field->offset = 0;
field->offset_state = GI_IR_OFFSETS_COMPUTED;
} }
else else
have_error = TRUE; have_error = TRUE;

View File

@@ -0,0 +1,168 @@
/*
* Copyright 2025 Philip Chimento <philip.chimento@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "girepository.h"
#include "glib.h"
#include "test-common.h"
static void
test_basic_struct_field (RepositoryFixture *fx,
const void *unused)
{
GIStructInfo *struct_info = NULL;
GIFieldInfo *field_info = NULL;
GITypeInfo *type_info = NULL;
GIFieldInfoFlags flags;
g_test_summary ("Test basic properties of a GIFieldInfo from a C struct");
struct_info = GI_STRUCT_INFO (gi_repository_find_by_name (fx->repository, "GLib", "DebugKey"));
g_assert_nonnull (struct_info);
field_info = gi_struct_info_get_field (struct_info, 0);
g_assert_true (GI_IS_FIELD_INFO (field_info));
g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (field_info)), ==, "key");
flags = gi_field_info_get_flags (field_info);
g_assert_cmpuint (flags, ==, GI_FIELD_IS_READABLE | GI_FIELD_IS_WRITABLE);
/* Guaranteed across platforms, because it's the first field */
g_assert_cmpuint (gi_field_info_get_offset (field_info), ==, 0);
type_info = gi_field_info_get_type_info (field_info);
g_assert_cmpuint (gi_type_info_get_tag (type_info), ==, GI_TYPE_TAG_UTF8);
g_assert_true (gi_type_info_is_pointer (type_info));
g_clear_pointer (&type_info, gi_base_info_unref);
g_clear_pointer (&field_info, gi_base_info_unref);
g_clear_pointer (&struct_info, gi_base_info_unref);
}
static void
test_basic_union_field (RepositoryFixture *fx,
const void *unused)
{
GIUnionInfo *union_info = NULL;
GIFieldInfo *field_info = NULL;
GITypeInfo *type_info = NULL;
GIFieldInfoFlags flags;
g_test_summary ("Test basic properties of a GIFieldInfo from a C union");
union_info = GI_UNION_INFO (gi_repository_find_by_name (fx->repository, "GLib", "DoubleIEEE754"));
g_assert_nonnull (union_info);
field_info = gi_union_info_get_field (union_info, 0);
g_assert_true (GI_IS_FIELD_INFO (field_info));
g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (field_info)), ==, "v_double");
flags = gi_field_info_get_flags (field_info);
g_assert_cmpuint (flags, ==, GI_FIELD_IS_READABLE | GI_FIELD_IS_WRITABLE);
/* Guaranteed across platforms, because union offsets are always 0 */
g_assert_cmpuint (gi_field_info_get_offset (field_info), ==, 0);
type_info = gi_field_info_get_type_info (field_info);
g_assert_cmpuint (gi_type_info_get_tag (type_info), ==, GI_TYPE_TAG_DOUBLE);
g_assert_false (gi_type_info_is_pointer (type_info));
g_clear_pointer (&type_info, gi_base_info_unref);
g_clear_pointer (&field_info, gi_base_info_unref);
g_clear_pointer (&union_info, gi_base_info_unref);
}
static void
test_read_write_struct_field (RepositoryFixture *fx,
const void *unused)
{
GIStructInfo *struct_info = NULL;
GIFieldInfo *field_info = NULL;
GDebugKey instance;
GIArgument arg;
gboolean ok;
g_test_summary ("Test reading and writing of a GIFieldInfo from a C union");
struct_info = GI_STRUCT_INFO (gi_repository_find_by_name (fx->repository, "GLib", "DebugKey"));
g_assert_nonnull (struct_info);
field_info = gi_struct_info_get_field (struct_info, 1);
g_assert_nonnull (field_info);
instance.value = 0xfeed;
ok = gi_field_info_get_field (field_info, &instance, &arg);
g_assert_true (ok);
g_assert_cmpuint (arg.v_uint, ==, 0xfeed);
arg.v_uint = 0x6502;
ok = gi_field_info_set_field (field_info, &instance, &arg);
g_assert_true (ok);
g_assert_cmpuint (instance.value, ==, 0x6502);
g_clear_pointer (&field_info, gi_base_info_unref);
g_clear_pointer (&struct_info, gi_base_info_unref);
}
static void
test_read_write_union_field (RepositoryFixture *fx,
const void *unused)
{
GIUnionInfo *union_info = NULL;
GIFieldInfo *field_info = NULL;
GDoubleIEEE754 instance;
GIArgument arg;
gboolean ok;
g_test_summary ("Test reading and writing of a GIFieldInfo from a C union");
union_info = GI_UNION_INFO (gi_repository_find_by_name (fx->repository, "GLib", "DoubleIEEE754"));
g_assert_nonnull (union_info);
field_info = gi_union_info_get_field (union_info, 0);
g_assert_nonnull (field_info);
instance.v_double = G_PI;
ok = gi_field_info_get_field (field_info, &instance, &arg);
g_assert_true (ok);
g_assert_cmpfloat (arg.v_double, ==, G_PI);
arg.v_double = G_E;
ok = gi_field_info_set_field (field_info, &instance, &arg);
g_assert_true (ok);
g_assert_cmpfloat (instance.v_double, ==, G_E);
g_clear_pointer (&field_info, gi_base_info_unref);
g_clear_pointer (&union_info, gi_base_info_unref);
}
int
main (int argc,
char *argv[])
{
repository_init (&argc, &argv);
ADD_REPOSITORY_TEST ("/field-info/basic-struct-field", test_basic_struct_field, &typelib_load_spec_glib);
ADD_REPOSITORY_TEST ("/field-info/basic-union-field", test_basic_union_field, &typelib_load_spec_glib);
ADD_REPOSITORY_TEST ("/field-info/read-write-struct-field", test_read_write_struct_field, &typelib_load_spec_glib);
ADD_REPOSITORY_TEST ("/field-info/read-write-union-field", test_read_write_union_field, &typelib_load_spec_glib);
return g_test_run ();
}

View File

@@ -46,6 +46,9 @@ if enable_gir
'callable-info' : { 'callable-info' : {
'depends': gio_gir_testing_dep, 'depends': gio_gir_testing_dep,
}, },
'field-info' : {
'depends': glib_gir_testing_dep,
},
'function-info' : { 'function-info' : {
'dependencies': [libffi_dep], 'dependencies': [libffi_dep],
'depends': glib_gir_testing_dep, 'depends': glib_gir_testing_dep,