From c9207edf32d966e67bccc1ed82cf0958de459817 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sat, 14 Dec 2024 00:19:31 +0100 Subject: Update the exploitation of the GObject memory hole. --- plugins/pychrysalide/glibext/Makefile.am | 1 + plugins/pychrysalide/glibext/module.c | 2 + plugins/pychrysalide/glibext/objhole.c | 292 +++++++++++++++++++++++++++++++ plugins/pychrysalide/glibext/objhole.h | 45 +++++ src/common/Makefile.am | 1 + src/glibext/Makefile.am | 4 +- src/glibext/objhole-int.h | 166 ++++++++++++++++++ src/glibext/objhole.c | 191 ++++++++++++++++++++ src/glibext/objhole.h | 114 +----------- tests/glibext/objhole.py | 22 +++ 10 files changed, 731 insertions(+), 107 deletions(-) create mode 100644 plugins/pychrysalide/glibext/objhole.c create mode 100644 plugins/pychrysalide/glibext/objhole.h create mode 100644 src/glibext/objhole-int.h create mode 100644 src/glibext/objhole.c create mode 100644 tests/glibext/objhole.py diff --git a/plugins/pychrysalide/glibext/Makefile.am b/plugins/pychrysalide/glibext/Makefile.am index e9f7c4c..007ceee 100644 --- a/plugins/pychrysalide/glibext/Makefile.am +++ b/plugins/pychrysalide/glibext/Makefile.am @@ -23,6 +23,7 @@ noinst_LTLIBRARIES = libpychrysaglibext.la libpychrysaglibext_la_SOURCES = \ constants.h constants.c \ module.h module.c \ + objhole.h objhole.c \ portion.h portion.c \ singleton.h singleton.c \ strbuilder.h strbuilder.c \ diff --git a/plugins/pychrysalide/glibext/module.c b/plugins/pychrysalide/glibext/module.c index 77e0c76..6cca246 100644 --- a/plugins/pychrysalide/glibext/module.c +++ b/plugins/pychrysalide/glibext/module.c @@ -40,6 +40,7 @@ #include "loadedpanel.h" #include "named.h" */ +#include "objhole.h" #include "portion.h" #include "singleton.h" #include "strbuilder.h" @@ -114,6 +115,7 @@ bool populate_glibext_module(void) if (result) result = ensure_python_singleton_candidate_is_registered(); if (result) result = ensure_python_string_builder_is_registered(); + if (result) result = ensure_python_thick_object_is_registered(); if (result) result = ensure_python_binary_portion_is_registered(); if (result) result = ensure_python_generic_work_is_registered(); if (result) result = ensure_python_singleton_factory_is_registered(); diff --git a/plugins/pychrysalide/glibext/objhole.c b/plugins/pychrysalide/glibext/objhole.c new file mode 100644 index 0000000..23f7f4c --- /dev/null +++ b/plugins/pychrysalide/glibext/objhole.c @@ -0,0 +1,292 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * objhole.c - équivalent Python du fichier "glibext/objhole.c" + * + * Copyright (C) 2024 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "objhole.h" + + +#include + + +#include +#include + + +#include "../access.h" +#include "../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(thick_object, G_TYPE_THICK_OBJECT); + + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_thick_object_init(PyObject *, PyObject *, PyObject *); + +/* Fournit la valeur courante de la zone de stockage d'un objet. */ +static PyObject *py_thick_object_get_extra(PyObject *, void *); + +/* Définit la valeur courante de la zone de stockage d'un objet. */ +static int py_thick_object_set_extra(PyObject *, PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_thick_object_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define THICK_OBJECT_DOC \ + "The ThickObject class is an alternative version of the GObject class." \ + " It provides an access to a 32-bit wide memory hole inside the native" \ + " GObject structure in order to exploit the area as various values" \ + " storage.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ThickObject()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la valeur courante de la zone de stockage d'un objet.* +* * +* Retour : Valeur de 32 lues et expurgées des bits GLib. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_thick_object_get_extra(PyObject *self, void *closure) +{ + PyObject *result; /* Résultat à retourner */ + GThickObject *obj; /* Version GLib de l'instance */ + guint extra; /* Valeur à transmettre */ + +#define THICK_OBJECT_EXTRA_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + extra, py_thick_object, \ + "Define and retrieve the data stored inside the structure" \ + " memory hole of all GObject native instances.\n" \ + "\n" \ + "Less than 32 bits are available for storing arbitrary values." \ +) + + obj = G_THICK_OBJECT(pygobject_get(self)); + + extra = g_thick_object_get_extra(obj); + + result = PyLong_FromUnsignedLong(extra); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = non utilisé ici. * +* * +* Description : Définit la valeur courante de la zone de stockage d'un objet.* +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_thick_object_set_extra(PyObject *self, PyObject *value, void *closure) +{ + unsigned long extra; /* Valeur à inscrire */ + GThickObject *obj; /* Version GLib de l'instance */ + + if (!PyLong_Check(value)) + { + PyErr_SetString(PyExc_TypeError, _("Invalid integer value")); + return -1; + } + + extra = PyLong_AsUnsignedLong(value); + + obj = G_THICK_OBJECT(pygobject_get(self)); + + g_thick_object_set_extra(obj, extra); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_thick_object_type(void) +{ + static PyMethodDef py_thick_object_methods[] = { + { NULL } + }; + + static PyGetSetDef py_thick_object_getseters[] = { + THICK_OBJECT_EXTRA_ATTRIB, + { NULL } + }; + + static PyTypeObject py_thick_object_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.glibext.ThickObject", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = THICK_OBJECT_DOC, + + .tp_methods = py_thick_object_methods, + .tp_getset = py_thick_object_getseters, + + .tp_init = py_thick_object_init, + .tp_new = py_thick_object_new, + + }; + + return &py_thick_object_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.glibext.ThickObject'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_thick_object_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ThickObject' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_thick_object_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.glibext"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_THICK_OBJECT, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en objet dense. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_thick_object(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_thick_object_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to thick object"); + break; + + case 1: + *((GThickObject **)dst) = G_THICK_OBJECT(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/glibext/objhole.h b/plugins/pychrysalide/glibext/objhole.h new file mode 100644 index 0000000..b541b70 --- /dev/null +++ b/plugins/pychrysalide/glibext/objhole.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * objhole.h - prototypes pour l'équivalent Python du fichier "glibext/objhole.h" + * + * Copyright (C) 2024 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_GLIBEXT_OBJHOLE_H +#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_OBJHOLE_H + + +#include +#include + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_thick_object_type(void); + +/* Prend en charge l'objet 'pychrysalide.glibext.ThickObject'. */ +bool ensure_python_thick_object_is_registered(void); + +/* Tente de convertir en objet dense. */ +int convert_to_thick_object(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_OBJHOLE_H */ diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 7925b66..687cb63 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -50,6 +50,7 @@ libcommon4_la_SOURCES = \ asm.h asm.c \ bits.h bits.c \ compiler.h \ + cpp.h \ datatypes.h \ dllist.h dllist.c \ entropy.h entropy.c \ diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am index 816f033..738f5b3 100644 --- a/src/glibext/Makefile.am +++ b/src/glibext/Makefile.am @@ -13,7 +13,7 @@ noinst_LTLIBRARIES = libglibext.la libglibextui.la # glinecursor.h glinecursor.c \ # gnhash.h gnhash.c \ # notifier.h \ -# objhole.h \ +# \ # proto.h \ # seq.h seq.c \ # _signal.h signal.c \ @@ -41,6 +41,8 @@ noinst_LTLIBRARIES = libglibext.la libglibextui.la libglibext_la_SOURCES = \ chrysamarshal.h chrysamarshal.c \ helpers.h \ + objhole-int.h \ + objhole.h objhole.c \ portion-int.h \ portion.h portion.c \ singleton-int.h \ diff --git a/src/glibext/objhole-int.h b/src/glibext/objhole-int.h new file mode 100644 index 0000000..b4abf6f --- /dev/null +++ b/src/glibext/objhole-int.h @@ -0,0 +1,166 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * objhole.h - définitions internes pour ll'utilisation d'un espace inutilisé dans la structure GObject + * + * Copyright (C) 2024 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see . + */ + + +#ifndef _GLIBEXT_OBJHOLE_INT_H +#define _GLIBEXT_OBJHOLE_INT_H + + +#include "objhole.h" + + +#include "../common/cpp.h" + + + +/** + * Une structure GObject a la définition suivante : + * + * struct _GObject + * { + * GTypeInstance g_type_instance; + * volatile guint ref_count; + * GData *qdata; + * }; + * + * Chaque objet GLib alloué comporte ainsi 4 octets inutilisés : + * + * (gdb) pt /o GObject + * type = struct _GObject { + * / 0 | 8 / GTypeInstance g_type_instance; + * / 8 | 4 / guint ref_count; + * / XXX 4-byte hole / + * / 16 | 8 / GData *qdata; + * + * / total size (bytes): 24 / + * } + * + * La situation n'a pas échappé aux développeurs GLib, avec la définition réelle + * de la structure (cf. https://github.com/GNOME/glib/blob/main/gobject/gobject.c) : + * + * #if SIZEOF_INT == 4 && GLIB_SIZEOF_VOID_P == 8 + * #define HAVE_OPTIONAL_FLAGS + * #endif + * + * typedef struct + * { + * GTypeInstance g_type_instance; + * guint ref_count; + * #ifdef HAVE_OPTIONAL_FLAGS + * guint optional_flags; + * #endif + * GData *qdata; + * } GObjectReal; + * + * G_STATIC_ASSERT(sizeof(GObject) == sizeof(GObjectReal)); + * G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, ref_count) == G_STRUCT_OFFSET(GObjectReal, ref_count)); + * G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, qdata) == G_STRUCT_OFFSET(GObjectReal, qdata)); + * + * L'espace entre les deux derniers champs ne peut donc être pleinement exploité deux fois. + */ + +/** + * Les bits effectivements utilisés par GLib s'identifie ainsi (02/12/24) : + * + * $ wget -qO /dev/stdout https://raw.githubusercontent.com/GNOME/glib/refs/heads/main/gobject/gobject.c \ + * | grep ' * #define OPTIONAL_FLAG_' + * #define OPTIONAL_FLAG_IN_CONSTRUCTION (1 << 0) + * #define OPTIONAL_FLAG_HAS_SIGNAL_HANDLER (1 << 1) + * #define OPTIONAL_FLAG_HAS_NOTIFY_HANDLER (1 << 2) + * #define OPTIONAL_FLAG_LOCK (1 << 3) + * #define OPTIONAL_FLAG_EVER_HAD_WEAK_REF (1 << 4) + * + * Les n premiers bits doivent ainsi être préservés, même s'il est possible de + * partager le bit de verrouilage OPTIONAL_FLAG_LOCK. + */ + + +#ifndef HAVE_OPTIONAL_FLAGS_IN_GOBJECT + +# if SIZEOF_INT == 4 && GLIB_SIZEOF_VOID_P >= 8 +# define HAVE_OPTIONAL_FLAGS_IN_GOBJECT 1 +# else +# define HAVE_OPTIONAL_FLAGS_IN_GOBJECT 0 +# endif + +#endif + + +/* Nouvelle version dense des objets (instance) */ +typedef struct _GThickObject +{ + /** + * (cf. structure GObjectReal officielle). + */ + + GTypeInstance g_type_instance; /* Type d'objet */ + guint ref_count; /* Décompte des références */ + +#ifdef HAVE_OPTIONAL_FLAGS_IN_GOBJECT + guint extra; /* Zone partagée avec GLib */ +#endif + + GData *qdata; /* Données complémentaires ? */ + +#ifndef HAVE_OPTIONAL_FLAGS_IN_GOBJECT + guint extra; /* Zone supplémentaire propre */ +#endif + +} GThickObject; + +/* Nouvelle version dense des objets (classe) */ +struct _GThickObjectClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/** + * Définition du périmètre et des moyens d'accès. + */ + +/* GLib 2.83.0 - cfa36f5e9 */ +#define GOBJECT_RESERVED_EXTRA_BITS 5 + +#define GET_GOBJECT_EXTRA(obj, tp) \ + ({ \ + BUILD_BUG_ON(sizeof(tp) > sizeof(guint)); \ + tp *___result; \ + guint __val; \ + __val = g_thick_object_get_extra(obj); \ + ___result = (tp *)(guint []){ __val }; \ + ___result; \ + }) + +#define SET_GOBJECT_EXTRA(obj, tp, data) \ + ({ \ + BUILD_BUG_ON(sizeof(tp) > sizeof(guint)); \ + BUILD_BUG_ON(sizeof(data) > sizeof(guint *)); \ + guint __val; \ + __val = *(guint *)data; \ + g_thick_object_set_extra(obj, __val); \ + }) + + + +#endif /* _GLIBEXT_OBJHOLE_INT_H */ diff --git a/src/glibext/objhole.c b/src/glibext/objhole.c new file mode 100644 index 0000000..20bb2a8 --- /dev/null +++ b/src/glibext/objhole.c @@ -0,0 +1,191 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * objhole.c - utilisation d'un espace inutilisé dans la structure GObject + * + * Copyright (C) 2024 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see . + */ + + +#include "objhole.h" + + +#include + + +#include "objhole-int.h" + + + +/* Initialise la classe des objets à la structure dense. */ +static void g_thick_object_class_init(GThickObjectClass *); + +/* Initialise une instance d'objet à la structure dense. */ +static void g_thick_object_init(GThickObject *); + +/* Supprime toutes les références externes. */ +static void g_thick_object_dispose(GThickObject *); + +/* Procède à la libération totale de la mémoire. */ +static void g_thick_object_finalize(GThickObject *); + + + +G_DEFINE_TYPE(GThickObject, g_thick_object, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des objets à la structure dense. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_thick_object_class_init(GThickObjectClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_thick_object_dispose; + object->finalize = (GObjectFinalizeFunc)g_thick_object_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : obj = instance à initialiser. * +* * +* Description : Initialise une instance d'objet à la structure dense. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_thick_object_init(GThickObject *obj) +{ + obj->extra = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : obj = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_thick_object_dispose(GThickObject *obj) +{ + G_OBJECT_CLASS(g_thick_object_parent_class)->dispose(G_OBJECT(obj)); + +} + + +/****************************************************************************** +* * +* Paramètres : obj = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_thick_object_finalize(GThickObject *obj) +{ + G_OBJECT_CLASS(g_thick_object_parent_class)->finalize(G_OBJECT(obj)); + +} + + +/****************************************************************************** +* * +* Paramètres : obj = instance d'objet GLib à consulter. * +* * +* Description : Fournit la valeur courante de la zone de stockage d'un objet.* +* * +* Retour : Valeur de 32 lues et expurgées des bits GLib. * +* * +* Remarques : - * +* * +******************************************************************************/ + +guint g_thick_object_get_extra(const GThickObject *obj) +{ + guint result; /* Valeur à retourner */ + guint mask; /* Masque à appliquer */ + + result = g_atomic_int_get(&obj->extra); + + assert(GOBJECT_RESERVED_EXTRA_BITS < 30); + + mask = (1 << GOBJECT_RESERVED_EXTRA_BITS) - 1; + + result &= ~mask; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : obj = instance d'objet GLib à consulter. * +* val = valeur de 32 à conserver. * +* * +* Description : Définit la valeur courante de la zone de stockage d'un objet.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_thick_object_set_extra(GThickObject *obj, guint val) +{ + guint mask; /* Masque à appliquer */ + + assert(GOBJECT_RESERVED_EXTRA_BITS < 30); + + mask = (1 << GOBJECT_RESERVED_EXTRA_BITS) - 1; + + assert((val & mask) == 0); + + val &= ~mask; + + g_atomic_int_and(&obj->extra, val | mask); + + g_atomic_int_or(&obj->extra, val); + +} diff --git a/src/glibext/objhole.h b/src/glibext/objhole.h index 38f4bd5..c1e8cf1 100644 --- a/src/glibext/objhole.h +++ b/src/glibext/objhole.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * objhole.h - prototypes pour l'utilisation d'un espace inutilisé dans la structure GObject * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2024 Cyrille Bagard * * This file is part of Chrysalide. * @@ -25,118 +25,20 @@ #define _GLIBEXT_OBJHOLE_H -#include -#include +#include "../glibext/helpers.h" -#include "../common/cpp.h" +#define G_TYPE_THICK_OBJECT (g_thick_object_get_type()) +DECLARE_GTYPE(GThickObject, g_thick_object, G, THICK_OBJECT); -/** - * Une structure GObject a la définition suivante : - * - * struct _GObject - * { - * GTypeInstance g_type_instance; - * volatile guint ref_count; - * GData *qdata; - * }; - * - * En revanche, le fichier "glib/gobject/gobject.c" précise la définition - * réelle de la structure selon l'environnement : - * - * #if SIZEOF_INT == 4 && GLIB_SIZEOF_VOID_P == 8 - * #define HAVE_OPTIONAL_FLAGS - * #endif - * - * typedef struct - * { - * GTypeInstance g_type_instance; - * guint ref_count; - * #ifdef HAVE_OPTIONAL_FLAGS - * guint optional_flags; - * #endif - * GData *qdata; - * } GObjectReal; - * - * G_STATIC_ASSERT(sizeof(GObject) == sizeof(GObjectReal)); - * G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, ref_count) == G_STRUCT_OFFSET(GObjectReal, ref_count)); - * G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, qdata) == G_STRUCT_OFFSET(GObjectReal, qdata)); - * - * L'espace entre les deux derniers champs ne peut donc être pleinement exploité deux fois. - */ - -#if 0 - -# define GET_GOBJECT_EXTRA(obj, tp) \ - ({ \ - BUILD_BUG_ON(sizeof(tp) > sizeof(guint)); \ - tp *___result; \ - ___result = (tp *)(((guint *)&obj->ref_count) + 1); \ - BUILD_BUG_ON((___result + 1) == (tp *)&obj->qdata); \ - ___result; \ - }) - -#endif - - -/** - * Choix du bit de verrou pour le champ "lock". - * - * Dans la structure exploitant le mot utilisé ici, ce verrou est généralement - * placé dans le bit de poids fort pour les objets qui l'utilisent. - */ - -#if __BYTE_ORDER == __LITTLE_ENDIAN - -# define HOLE_LOCK_BIT 31 - -#elif __BYTE_ORDER == __BIG_ENDIAN - -# define HOLE_LOCK_BIT 0 - -#else - -# error "Unknown byte order" - -#endif - - -/* Verrou d'accès pour une encapsulation */ -typedef struct _lockable_obj_extra_t -{ - gint lock; /* Gestion d'accès aux fanions */ - -} lockable_obj_extra_t; - - -#define INIT_GOBJECT_EXTRA_LOCK(xtr) \ - do \ - { \ - lockable_obj_extra_t *__lockable; \ - __lockable = (lockable_obj_extra_t *)xtr; \ - __lockable->lock = 0; \ - } \ - while (0) -#define LOCK_GOBJECT_EXTRA(xtr) \ - do \ - { \ - lockable_obj_extra_t *__lockable; \ - __lockable = (lockable_obj_extra_t *)xtr; \ - g_bit_lock(&__lockable->lock, HOLE_LOCK_BIT); \ - } \ - while (0) +/* Fournit la valeur courante de la zone de stockage d'un objet. */ +guint g_thick_object_get_extra(const GThickObject *); -#define UNLOCK_GOBJECT_EXTRA(xtr) \ - do \ - { \ - lockable_obj_extra_t *__lockable; \ - __lockable = (lockable_obj_extra_t *)xtr; \ - g_bit_unlock(&__lockable->lock, HOLE_LOCK_BIT); \ - } \ - while (0) +/* Définit la valeur courante de la zone de stockage d'un objet. */ +void g_thick_object_set_extra(GThickObject *, guint); diff --git a/tests/glibext/objhole.py b/tests/glibext/objhole.py new file mode 100644 index 0000000..09bd8f5 --- /dev/null +++ b/tests/glibext/objhole.py @@ -0,0 +1,22 @@ + +from chrysacase import ChrysalideTestCase +from pychrysalide.glibext import ThickObject + + +class TestWorks(ChrysalideTestCase): + """TestCase for pychrysalide.glibext.BinaryPortion""" + + def testExtraAccess(self): + """Access to various definitions of the extra data for ThickObject.""" + + obj = ThickObject() + + self.assertEqual(obj.extra, 0) + + obj.extra = 0xffffffe0 + + self.assertEqual(obj.extra, 0xffffffe0) + + obj.extra = 0x00123000 + + self.assertEqual(obj.extra, 0x00123000) -- cgit v0.11.2-87-g4458