From 7a60504691ebd8b914592e60990cc3526cf26e29 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 7 Mar 2021 18:52:38 +0100
Subject: Compact data type definitions.

---
 plugins/dexbnf/type.c                |  11 +-
 plugins/itanium/abi.c                |  20 ++-
 plugins/itanium/component.c          |   5 +-
 plugins/javadesc/field.c             |  15 +-
 plugins/pychrysalide/analysis/type.c |  22 ++-
 src/analysis/type-int.h              |  50 +++++-
 src/analysis/type.c                  | 302 +++++++++++++++++++++++++++++------
 src/analysis/type.h                  |  29 +++-
 src/analysis/types/proto.c           |  23 ++-
 9 files changed, 398 insertions(+), 79 deletions(-)

diff --git a/plugins/dexbnf/type.c b/plugins/dexbnf/type.c
index db838c1..b1e4155 100644
--- a/plugins/dexbnf/type.c
+++ b/plugins/dexbnf/type.c
@@ -66,6 +66,7 @@ static GDataType *dtd_full_class_name(input_buffer *buffer)
     size_t saved;                           /* Point de sauvegarde         */
     char next;                              /* Prochain caractère obtenu   */
     GDataType *ns;                          /* Espace de nom à attribuer   */
+    bool status;                            /* Bilan de rattachement       */
 
     /**
      * Les règles traitées sont les suivantes :
@@ -116,7 +117,15 @@ static GDataType *dtd_full_class_name(input_buffer *buffer)
 
         result = g_class_enum_type_new(CEK_CLASS, name);
 
-        g_data_type_set_namespace(result, ns, strdup("."));
+        status = g_data_type_set_namespace(result, ns, ".");
+
+        g_object_unref(G_OBJECT(ns));
+
+        if (!status)
+        {
+            g_clear_object(&result);
+            break;
+        }
 
     }
     while (1);
diff --git a/plugins/itanium/abi.c b/plugins/itanium/abi.c
index 213d5f7..393a8d6 100644
--- a/plugins/itanium/abi.c
+++ b/plugins/itanium/abi.c
@@ -2194,6 +2194,7 @@ static itanium_component *itd_builtin_type(GItaniumDemangling *context)
     GDataType *std;                         /* Espace de noms              */
     itanium_component *vendor;              /* Extension propriétaire      */
     GDataType *builtin;                     /* Type construit              */
+    bool status;                            /* Bilan de rattachement       */
 
     /**
      * La règle traitée ici est la suivante :
@@ -2351,7 +2352,16 @@ static itanium_component *itd_builtin_type(GItaniumDemangling *context)
                     std = g_class_enum_type_new(CEK_NAMESPACE, strdup("std"));
 
                     builtin = g_class_enum_type_new(CEK_CLASS, strdup("nullptr_t"));
-                    g_data_type_set_namespace(builtin, std, strdup("::"));
+                    status = g_data_type_set_namespace(builtin, std, "::");
+
+                    g_object_unref(G_OBJECT(std));
+
+                    if (!status)
+                    {
+                        g_object_unref(G_OBJECT(builtin));
+                        result = NULL;
+                        goto done;
+                    }
 
                     result = itd_make_type(builtin);
                     itd_set_type(result, ICT_STD_SUBST);
@@ -3438,6 +3448,7 @@ static itanium_component *itd_substitution(GItaniumDemangling *context)
     const itanium_std_subst_info *stdinfo;  /* Raccourci de confort        */
     GDataType *std;                         /* Espace de noms              */
     GDataType *type;                        /* Type complet final          */
+    bool status;                            /* Bilan de rattachement       */
 
     /**
      * La règle traitée ici est la suivante :
@@ -3488,7 +3499,12 @@ static itanium_component *itd_substitution(GItaniumDemangling *context)
                 else
                 {
                     type = g_class_enum_type_new(CEK_CLASS, strdup(stdinfo->class));
-                    g_data_type_set_namespace(type, std, strdup("::"));
+                    status = g_data_type_set_namespace(type, std, "::");
+                    g_object_unref(G_OBJECT(std));
+
+                    if (!status)
+                        break;
+
                 }
 
                 result = itd_make_type(type);
diff --git a/plugins/itanium/component.c b/plugins/itanium/component.c
index 558936a..b2f004b 100644
--- a/plugins/itanium/component.c
+++ b/plugins/itanium/component.c
@@ -1370,7 +1370,10 @@ static void itd_prepend_namespace_to_type(GDataType *type, GDataType *ns)
     existing = g_data_type_get_namespace(type);
 
     if (existing == NULL)
-        g_data_type_set_namespace(type, ns, strdup("::"));
+    {
+        g_data_type_set_namespace(type, ns, "::");
+        g_object_unref(G_OBJECT(ns));
+    }
 
     else
     {
diff --git a/plugins/javadesc/field.c b/plugins/javadesc/field.c
index 799d39d..6396e03 100644
--- a/plugins/javadesc/field.c
+++ b/plugins/javadesc/field.c
@@ -66,6 +66,7 @@ static GDataType *jtd_object_type_descriptor(input_buffer *buffer)
     GDataType *root;                        /* Espace de noms racine       */
     GDataType *ns;                          /* Espace de noms à attribuer  */
     GDataType *parent;                      /* Espace de noms parent       */
+    bool status;                            /* Bilan de rattachement       */
 
     result = NULL;
 
@@ -108,7 +109,7 @@ static GDataType *jtd_object_type_descriptor(input_buffer *buffer)
                 ns = g_data_type_get_namespace(result);
 
                 if (ns == NULL)
-                    g_data_type_set_namespace(result, root, strdup("."));
+                    status = g_data_type_set_namespace(result, root, ".");
 
                 else
                 {
@@ -118,12 +119,20 @@ static GDataType *jtd_object_type_descriptor(input_buffer *buffer)
                         ns = parent;
                     }
 
-                    g_data_type_set_namespace(ns, root, strdup("."));
+                    status = g_data_type_set_namespace(ns, root, ".");
 
                     g_object_unref(G_OBJECT(ns));
 
                 }
 
+                g_object_unref(G_OBJECT(root));
+
+                if (!status)
+                {
+                    g_clear_object(&result);
+                    goto error;
+                }
+
             }
 
             break;
@@ -156,6 +165,8 @@ static GDataType *jtd_object_type_descriptor(input_buffer *buffer)
     if (name != NULL)
         result = g_class_enum_type_new(CEK_CLASS, name);
 
+ error:
+
     return result;
 
 }
diff --git a/plugins/pychrysalide/analysis/type.c b/plugins/pychrysalide/analysis/type.c
index 1e4ec06..303d188 100644
--- a/plugins/pychrysalide/analysis/type.c
+++ b/plugins/pychrysalide/analysis/type.c
@@ -718,7 +718,7 @@ static PyObject *py_data_type_get_namespace(PyObject *self, void *closure)
     PyObject *result;                       /* Valeur à retourner          */
     GDataType *type;                        /* Elément à consulter         */
     GDataType *ns;                          /* Espace de noms              */
-    const char *sep;                        /* Séparateur d'espace         */
+    char *sep;                              /* Séparateur d'espace         */
 
 #define DATA_TYPE_NAMESPACE_ATTRIB PYTHON_GETSET_DEF_FULL               \
 (                                                                       \
@@ -744,13 +744,17 @@ static PyObject *py_data_type_get_namespace(PyObject *self, void *closure)
         g_object_unref(G_OBJECT(ns));
 
         PyTuple_SetItem(result, 1, PyUnicode_FromString(sep));
+        free(sep);
 
     }
 
     else
     {
+        assert(ns == NULL && sep == NULL);
+
         result = Py_None;
         Py_INCREF(result);
+
     }
 
     return result;
@@ -775,8 +779,9 @@ static PyObject *py_data_type_get_namespace(PyObject *self, void *closure)
 static int py_data_type_set_namespace(PyObject *self, PyObject *value, void *closure)
 {
     GDataType *type;                        /* Elément à traiter           */
+    bool status;                            /* Echec de l'inscription      */
     GDataType *ns;                          /* Espace de noms              */
-    char *sep;                              /* Séparateur des espaces      */
+    const char *sep;                        /* Séparateur des espaces      */
 
     if ((!PyTuple_Check(value) || (PyTuple_Check(value) && PyTuple_Size(value) != 2)) && value != Py_None)
     {
@@ -788,7 +793,7 @@ static int py_data_type_set_namespace(PyObject *self, PyObject *value, void *clo
     type = G_DATA_TYPE(pygobject_get(self));
 
     if (value == Py_None)
-        g_data_type_set_namespace(type, NULL, NULL);
+        status = g_data_type_set_namespace(type, NULL, NULL);
 
     else
     {
@@ -805,11 +810,16 @@ static int py_data_type_set_namespace(PyObject *self, PyObject *value, void *clo
         }
 
         ns = G_DATA_TYPE(pygobject_get(PyTuple_GetItem(value, 0)));
-        sep = strdup(PyUnicode_DATA(PyTuple_GetItem(value, 1)));
+        sep = PyUnicode_DATA(PyTuple_GetItem(value, 1));
+
+        status = g_data_type_set_namespace(type, ns, sep);
 
-        g_object_ref(G_OBJECT(ns));
-        g_data_type_set_namespace(type, ns, sep);
+    }
 
+    if (!status)
+    {
+        PyErr_SetString(PyExc_TypeError, _("Failed while registering the type namespace (!)"));
+        return -1;
     }
 
     return 0;
diff --git a/src/analysis/type-int.h b/src/analysis/type-int.h
index e14d209..d6c2588 100644
--- a/src/analysis/type-int.h
+++ b/src/analysis/type-int.h
@@ -29,6 +29,7 @@
 
 
 #include "storage/serialize-int.h"
+#include "../glibext/objhole.h"
 
 
 
@@ -58,18 +59,61 @@ typedef bool (* type_is_reference_fc) (const GDataType *);
 
 
 
+/* Informations glissées dans la structure GObject de GBinSymbol */
+typedef union _type_obj_extra
+{
+    struct
+    {
+        TypeQualifier qualifiers;           /* Eventuels qualificatifs     */
+        char ns_sep[2];                     /* Séparateur d'éléments       */
+        TypeFlag flags;                     /* Propriétés du type          */
+
+    };
+
+    gint lock;                              /* Gestion d'accès aux fanions */
+
+} type_obj_extra;
+
 /* Description de type quelconque (instance) */
 struct _GDataType
 {
     GObject parent;                         /* A laisser en premier        */
 
-    TypeQualifier qualifiers;               /* Eventuels qualificatifs     */
-
     GDataType *namespace;                   /* Espace de noms / classe     */
-    char *ns_sep;                           /* Séparateur d'éléments       */
+
+#if __SIZEOF_INT__ == __SIZEOF_LONG__
+
+    /**
+     * L'inclusion des informations suivantes dépend de l'architecture.
+     *
+     * Si la structure GObject possède un trou, on remplit de préférence
+     * ce dernier.
+     */
+
+    type_obj_extra extra;                   /* Externalisation embarquée   */
+
+#endif
 
 };
 
+/**
+ * Accès aux informations éventuellement déportées.
+ */
+
+#if __SIZEOF_INT__ == __SIZEOF_LONG__
+
+#   define INIT_DATA_TYPE_EXTRA(tp) tp->extra.lock = 0
+
+#   define GET_DATA_TYPE_EXTRA(tp) &tp->extra
+
+#else
+
+#   define INIT_DATA_TYPE_EXTRA(tp) INIT_GOBJECT_EXTRA(G_OBJECT(tp))
+
+#   define GET_DATA_TYPE_EXTRA(tp) GET_GOBJECT_EXTRA(G_OBJECT(tp), type_obj_extra)
+
+#endif
+
 /* Description de type quelconque (classe) */
 struct _GDataTypeClass
 {
diff --git a/src/analysis/type.c b/src/analysis/type.c
index a5cc46c..4a0b7d8 100644
--- a/src/analysis/type.c
+++ b/src/analysis/type.c
@@ -24,6 +24,7 @@
 #include "type.h"
 
 
+#include <assert.h>
 #include <malloc.h>
 #include <string.h>
 
@@ -109,10 +110,11 @@ static void g_data_type_class_init(GDataTypeClass *klass)
 
 static void g_data_type_init(GDataType *type)
 {
+    INIT_DATA_TYPE_EXTRA(type);
+
     g_data_type_set_qualifiers(type, TQF_NONE);
 
     type->namespace = NULL;
-    type->ns_sep = NULL;
 
 }
 
@@ -172,9 +174,6 @@ static void g_data_type_dispose(GDataType *type)
 
 static void g_data_type_finalize(GDataType *type)
 {
-    if (type->ns_sep != NULL)
-        free(type->ns_sep);
-
     G_OBJECT_CLASS(g_data_type_parent_class)->finalize(G_OBJECT(type));
 
 }
@@ -197,27 +196,35 @@ static void g_data_type_finalize(GDataType *type)
 static bool _g_data_type_load(GDataType *type, GObjectStorage *storage, packed_buffer *pbuf)
 {
     bool result;                            /* Bilan à retourner           */
-    uint8_t has_ns;                         /* Association d'un espace ?   */
     uleb128_t value;                        /* Valeur ULEB128 à charger    */
+    char ns_sep[2];                         /* Séparateur d'éléments       */
+    GDataType *namespace;                   /* Espace de noms / classe     */
 
     result = unpack_uleb128(&value, pbuf);
     if (!result) goto exit;
 
     g_data_type_set_qualifiers(type, value);
 
-    result = extract_packed_buffer(pbuf, &has_ns, sizeof(uint8_t), false);
+    result = unpack_uleb128(&value, pbuf);
+    if (!result) goto exit;
+
+    g_data_type_set_flags(type, value);
+
+    result = extract_packed_buffer(pbuf, ns_sep, 2 * sizeof(char), false);
     if (!result) goto exit;
 
-    if (has_ns == 0x01)
+    if (ns_sep[0] != '\0')
     {
-        result = g_data_type_load(type->namespace, storage, pbuf);
-        if (!result) goto exit;
+        //result = g_data_type_load(type->namespace, storage, pbuf); // TODO
+        namespace = NULL;
 
-        result = unpack_uleb128(&value, pbuf);
+        result = (namespace != NULL);
         if (!result) goto exit;
 
-        type->ns_sep = calloc(value, sizeof(char));
-        result = extract_packed_buffer(pbuf, type->ns_sep, value, false);
+        result = g_data_type_set_namespace(type, namespace, ns_sep);
+        assert(result);
+
+        g_object_unref(G_OBJECT(namespace));
 
     }
 
@@ -273,31 +280,34 @@ static bool g_data_type_load(GDataType *type, GObjectStorage *storage, packed_bu
 static bool _g_data_type_store(const GDataType *type, GObjectStorage *storage, packed_buffer *pbuf)
 {
     bool result;                            /* Bilan à retourner           */
-    uint8_t has_ns;                         /* Association d'un espace ?   */
-    size_t ns_sep_len;                      /* Taille du séparateur        */
+    type_obj_extra *extra;                  /* Données insérées à modifier */
 
     result = pack_uleb128((uleb128_t []){ g_data_type_get_qualifiers(type) }, pbuf);
     if (!result) goto exit;
 
-    has_ns = (type->namespace != NULL ? 0x01 : 0x00);
-
-    result = extend_packed_buffer(pbuf, &has_ns, sizeof(uint8_t), false);
+    result = pack_uleb128((uleb128_t []){ g_data_type_get_flags(type) }, pbuf);
     if (!result) goto exit;
 
-    if (type->namespace != NULL)
-    {
-        result = g_data_type_store(type->namespace, storage, pbuf);
-        if (!result) goto exit;
+    extra = GET_DATA_TYPE_EXTRA(type);
 
-        ns_sep_len = strlen(type->ns_sep);
+    g_bit_lock(&extra->lock, HOLE_LOCK_BIT);
 
-        result = pack_uleb128((uleb128_t []){ ns_sep_len }, pbuf);
-        if (!result) goto exit;
+    result = extend_packed_buffer(pbuf, extra->ns_sep, 2 * sizeof(char), false);
+    if (!result) goto unlocking_exit;
+
+    if (extra->ns_sep[0] != '\0')
+    {
+        assert(type->namespace != NULL);
 
-        result = extend_packed_buffer(pbuf, type->ns_sep, ns_sep_len, false);
+        result = g_data_type_store(type->namespace, storage, pbuf);
+        if (!result) goto unlocking_exit;
 
     }
 
+ unlocking_exit:
+
+    g_bit_unlock(&extra->lock, HOLE_LOCK_BIT);
+
  exit:
 
     return result;
@@ -380,23 +390,39 @@ GDataType *g_data_type_dup(const GDataType *type)
 {
     GDataType *result;                      /* Copie à retourner           */
     GDataTypeClass *class;                  /* Classe du type              */
+    type_obj_extra *extra;                  /* Données insérées à modifier */
     GDataType *ns;                          /* Eventuel espace de noms     */
-    char *ns_sep;                           /* Séparation des espaces      */
+    bool status;                            /* Bilan d'un rattachement     */
 
     class = G_DATA_TYPE_GET_CLASS(type);
 
     result = class->dup(type);
 
-    if (type->namespace != NULL)
+    g_data_type_set_qualifiers(result, g_data_type_get_qualifiers(type));
+
+    g_data_type_set_flags(result, g_data_type_get_flags(type));
+
+    extra = GET_DATA_TYPE_EXTRA(type);
+
+    g_bit_lock(&extra->lock, HOLE_LOCK_BIT);
+
+    if (extra->ns_sep[0] != '\0')
     {
+        assert(type->namespace != NULL);
+
         ns = g_data_type_dup(type->namespace);
-        ns_sep = type->ns_sep != NULL ? strdup(type->ns_sep) : NULL;
 
-        g_data_type_set_namespace(result, ns, ns_sep);
+        status = g_data_type_set_namespace(result, ns, extra->ns_sep);
+        assert(status);
+
+        g_object_unref(G_OBJECT(ns));
+
+        if (!status)
+            g_clear_object(&result);
 
     }
 
-    result->qualifiers = type->qualifiers;
+    g_bit_unlock(&extra->lock, HOLE_LOCK_BIT);
 
     return result;
 
@@ -420,7 +446,9 @@ char *g_data_type_to_string(const GDataType *type, bool include)
 {
     char *result;                           /* Chaîne à retourner          */
     GDataTypeClass *class;                  /* Classe du type              */
+    type_obj_extra *extra;                  /* Données insérées à modifier */
     char *namespace;                        /* Groupe d'appartenance       */
+    TypeQualifier qualifiers;               /* Qualificatifs du type       */
 
     class = G_DATA_TYPE_GET_CLASS(type);
 
@@ -429,24 +457,36 @@ char *g_data_type_to_string(const GDataType *type, bool include)
     if (result == NULL)
         result = strdup("");
 
-    if (include && type->namespace != NULL && g_data_type_handle_namespaces(type))
+    if (include)
     {
-        namespace = g_data_type_to_string(type->namespace, true);
+        extra = GET_DATA_TYPE_EXTRA(type);
+
+        g_bit_lock(&extra->lock, HOLE_LOCK_BIT);
 
-        result = strprep(result, type->ns_sep);
-        result = strprep(result, namespace);
+        if (type->namespace != NULL && g_data_type_handle_namespaces(type))
+        {
+            namespace = g_data_type_to_string(type->namespace, true);
 
-        free(namespace);
+            result = strprep(result, extra->ns_sep);
+            result = strprep(result, namespace);
+
+            free(namespace);
+
+        }
+
+        g_bit_unlock(&extra->lock, HOLE_LOCK_BIT);
 
     }
 
-    if (type->qualifiers & TQF_RESTRICT)
+    qualifiers = g_data_type_get_qualifiers(type);
+
+    if (qualifiers & TQF_RESTRICT)
         result = strprep(result, "restrict ");
 
-    if (type->qualifiers & TQF_VOLATILE)
+    if (qualifiers & TQF_VOLATILE)
         result = strprep(result, "volatile ");
 
-    if (type->qualifiers & TQF_CONST)
+    if (qualifiers & TQF_CONST)
         result = strprep(result, "const ");
 
     return result;
@@ -457,7 +497,7 @@ char *g_data_type_to_string(const GDataType *type, bool include)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : type       = instance à mettre à jour.                       *
-*                qualifiers = nouveaux qualificatifs pour la variable.        *
+*                qualifiers = nouveaux qualificatifs pour le type.            *
 *                                                                             *
 *  Description : Définit l'ensemble des qualificatifs d'une instance de type. *
 *                                                                             *
@@ -469,7 +509,15 @@ char *g_data_type_to_string(const GDataType *type, bool include)
 
 void g_data_type_set_qualifiers(GDataType *type, TypeQualifier qualifiers)
 {
-    type->qualifiers = qualifiers;
+    type_obj_extra *extra;                  /* Données insérées à modifier */
+
+    extra = GET_DATA_TYPE_EXTRA(type);
+
+    g_bit_lock(&extra->lock, HOLE_LOCK_BIT);
+
+    extra->qualifiers = qualifiers;
+
+    g_bit_unlock(&extra->lock, HOLE_LOCK_BIT);
 
 }
 
@@ -477,7 +525,7 @@ void g_data_type_set_qualifiers(GDataType *type, TypeQualifier qualifiers)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : type      = instance à mettre à jour.                        *
-*                qualifier = nouveau qualificatif pour la variable.           *
+*                qualifier = nouveau qualificatif pour le type.               *
 *                                                                             *
 *  Description : Ajoute un qualificatif à une instance de type.               *
 *                                                                             *
@@ -489,7 +537,15 @@ void g_data_type_set_qualifiers(GDataType *type, TypeQualifier qualifiers)
 
 void g_data_type_add_qualifier(GDataType *type, TypeQualifier qualifier)
 {
-    type->qualifiers |= qualifier;
+    type_obj_extra *extra;                  /* Données insérées à modifier */
+
+    extra = GET_DATA_TYPE_EXTRA(type);
+
+    g_bit_lock(&extra->lock, HOLE_LOCK_BIT);
+
+    extra->qualifiers |= qualifier;
+
+    g_bit_unlock(&extra->lock, HOLE_LOCK_BIT);
 
 }
 
@@ -509,8 +565,15 @@ void g_data_type_add_qualifier(GDataType *type, TypeQualifier qualifier)
 TypeQualifier g_data_type_get_qualifiers(const GDataType *type)
 {
     TypeQualifier result;                   /* Qualificatifs à renvoyer    */
+    type_obj_extra *extra;                  /* Données insérées à modifier */
 
-    result = type->qualifiers;
+    extra = GET_DATA_TYPE_EXTRA(type);
+
+    g_bit_lock(&extra->lock, HOLE_LOCK_BIT);
+
+    result = extra->qualifiers;
+
+    g_bit_unlock(&extra->lock, HOLE_LOCK_BIT);
 
     return result;
 
@@ -525,22 +588,48 @@ TypeQualifier g_data_type_get_qualifiers(const GDataType *type)
 *                                                                             *
 *  Description : Définit le groupe d'appartenance d'un type donné.            *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : true si la définition est effective, false en cas de rejet.  *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-void g_data_type_set_namespace(GDataType *type, GDataType *namespace, char *sep)
+bool g_data_type_set_namespace(GDataType *type, GDataType *namespace, const char *sep)
 {
-    if (type->namespace != NULL)
-        g_object_unref(G_OBJECT(type->namespace));
+    bool result;                            /* Bilan à retourner           */
+    type_obj_extra *extra;                  /* Données insérées à modifier */
+
+    result = ((namespace == NULL && sep == NULL) || (namespace != NULL && sep != NULL && sep[0] != '\0'));
+
+    if (result)
+    {
+        extra = GET_DATA_TYPE_EXTRA(type);
+
+        g_bit_lock(&extra->lock, HOLE_LOCK_BIT);
+
+        if (sep == NULL)
+        {
+            extra->ns_sep[0] = '\0';
+            extra->ns_sep[1] = '\0';
+        }
+        else
+        {
+            extra->ns_sep[0] = sep[0];
+            extra->ns_sep[1] = sep[1];
+        }
+
+        if (type->namespace != NULL)
+            g_object_unref(G_OBJECT(type->namespace));
 
-    if (type->ns_sep != NULL)
-        free(type->ns_sep);
+        type->namespace = namespace;
+
+        g_object_ref(G_OBJECT(namespace));
+
+        g_bit_unlock(&extra->lock, HOLE_LOCK_BIT);
+
+    }
 
-    type->namespace = namespace;
-    type->ns_sep = sep;
+    return result;
 
 }
 
@@ -560,12 +649,19 @@ void g_data_type_set_namespace(GDataType *type, GDataType *namespace, char *sep)
 GDataType *g_data_type_get_namespace(const GDataType *type)
 {
     GDataType *result;                      /* Espace à renvoyer           */
+    type_obj_extra *extra;                  /* Données insérées à modifier */
+
+    extra = GET_DATA_TYPE_EXTRA(type);
+
+    g_bit_lock(&extra->lock, HOLE_LOCK_BIT);
 
     result = type->namespace;
 
     if (result != NULL)
         g_object_ref(G_OBJECT(result));
 
+    g_bit_unlock(&extra->lock, HOLE_LOCK_BIT);
+
     return result;
 
 }
@@ -583,11 +679,25 @@ GDataType *g_data_type_get_namespace(const GDataType *type)
 *                                                                             *
 ******************************************************************************/
 
-const char *g_data_type_get_namespace_separator(const GDataType *type)
+char *g_data_type_get_namespace_separator(const GDataType *type)
 {
     char *result;                           /* Séparateur à retourner      */
+    type_obj_extra *extra;                  /* Données insérées à modifier */
+
+    extra = GET_DATA_TYPE_EXTRA(type);
+
+    g_bit_lock(&extra->lock, HOLE_LOCK_BIT);
+
+    if (extra->ns_sep[0] == '\0')
+        result = NULL;
+
+    else if (extra->ns_sep[1] == '\0')
+        result = strndup(extra->ns_sep, 1);
 
-    result = type->ns_sep;
+    else
+        result = strndup(extra->ns_sep, 2);
+
+    g_bit_unlock(&extra->lock, HOLE_LOCK_BIT);
 
     return result;
 
@@ -625,6 +735,92 @@ bool g_data_type_handle_namespaces(const GDataType *type)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : type       = instance à mettre à jour.                       *
+*                flags = nouvelles propriétés pour le type.                   *
+*                                                                             *
+*  Description : Définit l'ensemble des fanions d'une instance de type.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_data_type_set_flags(GDataType *type, TypeFlag flags)
+{
+    type_obj_extra *extra;                  /* Données insérées à modifier */
+
+    extra = GET_DATA_TYPE_EXTRA(type);
+
+    g_bit_lock(&extra->lock, HOLE_LOCK_BIT);
+
+    extra->flags = flags;
+
+    g_bit_unlock(&extra->lock, HOLE_LOCK_BIT);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type      = instance à mettre à jour.                        *
+*                flag = nouvelle propriété pour le type.                      *
+*                                                                             *
+*  Description : Ajoute un fanion à une instance de type.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_data_type_add_flag(GDataType *type, TypeFlag flag)
+{
+    type_obj_extra *extra;                  /* Données insérées à modifier */
+
+    extra = GET_DATA_TYPE_EXTRA(type);
+
+    g_bit_lock(&extra->lock, HOLE_LOCK_BIT);
+
+    extra->flags |= flag;
+
+    g_bit_unlock(&extra->lock, HOLE_LOCK_BIT);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = instance à consulter.                                 *
+*                                                                             *
+*  Description : Fournit les fanions associés à une instance de type.         *
+*                                                                             *
+*  Retour      : Qualificatifs éventuels.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+TypeFlag g_data_type_get_flags(const GDataType *type)
+{
+    TypeFlag result;                        /* Propriétés à renvoyer       */
+    type_obj_extra *extra;                  /* Données insérées à modifier */
+
+    extra = GET_DATA_TYPE_EXTRA(type);
+
+    g_bit_lock(&extra->lock, HOLE_LOCK_BIT);
+
+    result = extra->flags;
+
+    g_bit_unlock(&extra->lock, HOLE_LOCK_BIT);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : type = type à consulter.                                     *
 *                                                                             *
 *  Description : Indique si le type est un pointeur.                          *
diff --git a/src/analysis/type.h b/src/analysis/type.h
index f21c008..819af38 100644
--- a/src/analysis/type.h
+++ b/src/analysis/type.h
@@ -51,13 +51,23 @@ typedef enum _TypeQualifier
     TQF_NONE        = (0 << 0),             /* Néant                       */
     TQF_RESTRICT    = (1 << 0),             /* restrict (C99)              */
     TQF_VOLATILE    = (1 << 1),             /* volatile                    */
-    TQF_CONST       = (1 << 2)              /* const                       */
+    TQF_CONST       = (1 << 2),             /* const                       */
+
+    TQF_ALL         = ((1 << 3) - 1)        /* Masque de qualificatifs     */
 
 } TypeQualifier;
 
+/* Propriétés particulières d'un type */
+typedef enum _TypeFlag
+{
+    TFL_NONE            = (0 << 0),         /* Aucune propriété            */
+    TFL_SINGLETON_SOON  = (1 << 0),         /* Singleton en devenir        */
+    TFL_SINGLETON       = (1 << 1),         /* Singleton effectif          */
+
+    TFL_USER_LOW_BIT    = (1 << 2),         /* Premier bit libre           */
+    TFL_USER_HIGH_BIT   = (1 << 6)          /* Dernier bit libre           */
 
-/* Masque de tous les qualificatifs */
-#define TQF_ALL ((1 << 3) - 1)
+} TypeFlag;
 
 
 /* Indique le type défini pour un type quelconque. */
@@ -82,17 +92,26 @@ void g_data_type_add_qualifier(GDataType *, TypeQualifier);
 TypeQualifier g_data_type_get_qualifiers(const GDataType *);
 
 /* Définit le groupe d'appartenance d'un type donné. */
-void g_data_type_set_namespace(GDataType *, GDataType *, char *);
+bool g_data_type_set_namespace(GDataType *, GDataType *, const char *);
 
 /* Fournit le groupe d'appartenance d'un type donné. */
 GDataType *g_data_type_get_namespace(const GDataType *);
 
 /* Fournit la chaîne de séparation entre deux entités. */
-const char *g_data_type_get_namespace_separator(const GDataType *);
+char *g_data_type_get_namespace_separator(const GDataType *);
 
 /* Indique si le type assure une gestion des espaces de noms. */
 bool g_data_type_handle_namespaces(const GDataType *);
 
+/* Définit l'ensemble des fanions d'une instance de type. */
+void g_data_type_set_flags(GDataType *, TypeFlag);
+
+/* Ajoute un fanion à une instance de type. */
+void g_data_type_add_flag(GDataType *, TypeFlag);
+
+/* Fournit les fanions associés à une instance de type. */
+TypeFlag g_data_type_get_flags(const GDataType *);
+
 /* Indique si le type est un pointeur. */
 bool g_data_type_is_pointer(const GDataType *);
 
diff --git a/src/analysis/types/proto.c b/src/analysis/types/proto.c
index aa096d8..4df0552 100644
--- a/src/analysis/types/proto.c
+++ b/src/analysis/types/proto.c
@@ -396,6 +396,7 @@ static char *g_proto_type_to_string(const GProtoType *type, bool include)
 {
     char *result;                           /* Valeur à renvoyer           */
     GDataType *base;                        /* Version d'instance parente  */
+    type_obj_extra *extra;                  /* Données insérées à modifier */
     char *namespace;                        /* Groupe d'appartenance       */
     size_t i;                               /* Boucle de parcours          */
     char *arg;                              /* Argument à décrire          */
@@ -415,15 +416,25 @@ static char *g_proto_type_to_string(const GProtoType *type, bool include)
 
     base = G_DATA_TYPE(type);
 
-    if (include && base->namespace != NULL)
+    if (include)
     {
-        namespace = g_data_type_to_string(base->namespace, true);
-        if (namespace == NULL) goto error;
+        extra = GET_DATA_TYPE_EXTRA(base);
 
-        result = stradd(result, namespace);
-        result = stradd(result, base->ns_sep);
+        g_bit_lock(&extra->lock, HOLE_LOCK_BIT);
 
-        free(namespace);
+        if (base->namespace != NULL)
+        {
+            namespace = g_data_type_to_string(base->namespace, true);
+            if (namespace == NULL) goto error;
+
+            result = strprep(result, extra->ns_sep);
+            result = strprep(result, namespace);
+
+            free(namespace);
+
+        }
+
+        g_bit_unlock(&extra->lock, HOLE_LOCK_BIT);
 
     }
 
-- 
cgit v0.11.2-87-g4458