From 5863af232b8fc57de210702afe659a7383bb8840 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 9 Feb 2019 14:01:58 +0100
Subject: Fixed another batch of memory leaks.

---
 plugins/arm/v7/fetch.c                  |   3 +
 plugins/itanium/component.c             |  13 ++-
 plugins/pychrysalide/access.c           |  22 ++++-
 plugins/pychrysalide/access.h           |   3 +
 plugins/pychrysalide/analysis/project.c |   3 +
 plugins/pychrysalide/helpers.c          |   4 +
 plugins/pychrysalide/plugin.c           |  37 ++++++---
 plugins/pychrysalide/pychrysa.c         |  24 +++++-
 src/analysis/db/collection.c            |  14 ++++
 src/analysis/project.c                  |   3 +
 src/analysis/routine.c                  |   6 +-
 src/gleak.c                             | 137 +++++++++++++++++++++++++++++++-
 src/gleak.h                             |   2 +
 src/main.c                              |   4 +
 src/plugins/plugin-def.h                |  20 +++--
 15 files changed, 264 insertions(+), 31 deletions(-)

diff --git a/plugins/arm/v7/fetch.c b/plugins/arm/v7/fetch.c
index 0aa0c6c..6252990 100644
--- a/plugins/arm/v7/fetch.c
+++ b/plugins/arm/v7/fetch.c
@@ -498,6 +498,9 @@ void help_fetching_with_instruction_ldr_literal_with_orig(GArchInstruction *inst
         {
             g_db_comment_add_static_text(comment, "\n");
             g_db_comment_add_dynamic_text(comment, desc);
+
+            g_object_unref(G_OBJECT(comment));
+
         }
 
         else
diff --git a/plugins/itanium/component.c b/plugins/itanium/component.c
index 5ebfeb9..7510b42 100644
--- a/plugins/itanium/component.c
+++ b/plugins/itanium/component.c
@@ -1408,8 +1408,17 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
 
                 result = itd_translate_component_to_type(comp->binary.right);
 
-                if (result != NULL && ns != NULL)
-                    itd_prepend_namespace_to_type(result, ns);
+                if (result != NULL)
+                {
+                    if (ns != NULL)
+                        itd_prepend_namespace_to_type(result, ns);
+                }
+
+                else
+                {
+                    if (ns != NULL)
+                        g_object_unref(G_OBJECT(ns));
+                }
 
             }
 
diff --git a/plugins/pychrysalide/access.c b/plugins/pychrysalide/access.c
index bfaf160..4efa9c7 100644
--- a/plugins/pychrysalide/access.c
+++ b/plugins/pychrysalide/access.c
@@ -95,8 +95,6 @@ void register_access_to_python_module(const char *path, PyObject *mod)
     access.path = path;
     access.mod = mod;
 
-    Py_INCREF(mod);
-
     _pychrysalide_modules = qinsert(_pychrysalide_modules, &_pychrysalide_count,
                                     sizeof(module_access), (__compar_fn_t)compare_python_module_accesses,
                                     &access);
@@ -135,3 +133,23 @@ PyObject *get_access_to_python_module(const char *path)
     return result;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Supprime tous les accès rapide aux modules Python.           *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void clear_all_accesses_to_python_modules(void)
+{
+    if (_pychrysalide_modules != NULL)
+        free(_pychrysalide_modules);
+
+}
diff --git a/plugins/pychrysalide/access.h b/plugins/pychrysalide/access.h
index 492664d..9a842e4 100644
--- a/plugins/pychrysalide/access.h
+++ b/plugins/pychrysalide/access.h
@@ -35,6 +35,9 @@ void register_access_to_python_module(const char *, PyObject *);
 /* Fournit la référence à un module Python défini. */
 PyObject *get_access_to_python_module(const char *path);
 
+/* Supprime tous les accès rapide aux modules Python. */
+void clear_all_accesses_to_python_modules(void);
+
 
 
 #endif  /* _PLUGINS_PYCHRYSALIDE_ACCESS_H */
diff --git a/plugins/pychrysalide/analysis/project.c b/plugins/pychrysalide/analysis/project.c
index 9046bf3..98610d5 100644
--- a/plugins/pychrysalide/analysis/project.c
+++ b/plugins/pychrysalide/analysis/project.c
@@ -308,6 +308,9 @@ static PyObject *py_study_project_get_contents(PyObject *self, void *closure)
 
     }
 
+    if (contents != NULL)
+        free(contents);
+
     return result;
 
 }
diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c
index f744475..48b805c 100644
--- a/plugins/pychrysalide/helpers.c
+++ b/plugins/pychrysalide/helpers.c
@@ -434,6 +434,8 @@ bool register_python_module_methods(PyObject *module, PyMethodDef *defs)
 
             if (result)
             {
+                Py_INCREF(item);
+
                 ret = PyDict_SetItemString(features_dict, iter->ml_name, item);
                 result = (ret == 0);
                 assert(result);
@@ -483,6 +485,8 @@ static bool include_python_type_into_features(PyObject *dict, PyTypeObject *type
     result = (item != NULL);
     assert(result);
 
+    Py_INCREF(item);
+
     ret = PyDict_SetItemString(features_dict, name, item);
     result = (ret == 0);
     assert(result);
diff --git a/plugins/pychrysalide/plugin.c b/plugins/pychrysalide/plugin.c
index 51da910..9352924 100644
--- a/plugins/pychrysalide/plugin.c
+++ b/plugins/pychrysalide/plugin.c
@@ -94,9 +94,6 @@ struct _GPythonPlugin
 {
     GPluginModule parent;                   /* Instance parente            */
 
-    PyObject *module;                       /* Script Python chargé        */
-    PyObject *instance;                     /* Instance Python du greffon  */
-
 };
 
 
@@ -551,6 +548,8 @@ static void py_plugin_module_handle_binary_content_wrapper(const GPluginModule *
     Py_XDECREF(value);
     Py_DECREF(args);
 
+    Py_DECREF(pyobj);
+
     PyGILState_Release(gstate);
 
 }
@@ -597,6 +596,8 @@ static void py_plugin_module_handle_loaded_content_wrapper(const GPluginModule *
     Py_XDECREF(value);
     Py_DECREF(args);
 
+    Py_DECREF(pyobj);
+
     PyGILState_Release(gstate);
 
 }
@@ -643,6 +644,8 @@ static bool py_plugin_module_handle_binary_format_analysis_wrapper(const GPlugin
     Py_XDECREF(value);
     Py_DECREF(args);
 
+    Py_DECREF(pyobj);
+
     PyGILState_Release(gstate);
 
     return true;
@@ -691,6 +694,8 @@ static bool py_plugin_module_preload_binary_format_wrapper(const GPluginModule *
     Py_XDECREF(value);
     Py_DECREF(args);
 
+    Py_DECREF(pyobj);
+
     PyGILState_Release(gstate);
 
     return true;
@@ -735,6 +740,8 @@ static void py_plugin_module_attach_debug_format_wrapper(const GPluginModule *pl
     Py_XDECREF(value);
     Py_DECREF(args);
 
+    Py_DECREF(pyobj);
+
     PyGILState_Release(gstate);
 
 }
@@ -781,6 +788,8 @@ static void py_plugin_module_process_disassembly_event_wrapper(const GPluginModu
     Py_XDECREF(value);
     Py_DECREF(args);
 
+    Py_DECREF(pyobj);
+
     PyGILState_Release(gstate);
 
 }
@@ -903,9 +912,6 @@ static void g_python_plugin_dispose(GPythonPlugin *plugin)
     if (tstate != NULL)
         PyEval_RestoreThread(tstate);
 
-    Py_XDECREF(plugin->instance);
-    plugin->instance = NULL;
-
     if (tstate != NULL)
         PyEval_SaveThread();
 
@@ -930,15 +936,20 @@ static void g_python_plugin_finalize(GPythonPlugin *plugin)
 {
     plugin_interface *final;                /* Interface finale conservée  */
 
-    Py_XDECREF(plugin->module);
-
     final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface;
 
     if (final != NULL)
     {
+        free(final->name);
+        free(final->desc);
+        free(final->version);
+
         assert(final->required_count == 1);
         free(final->required);
 
+        if (final->actions != NULL)
+            free(final->actions);
+
         free(final);
 
     }
@@ -1025,10 +1036,14 @@ GPluginModule *g_python_plugin_new(const char *modname, const char *filename)
 
     G_PLUGIN_MODULE(result)->filename = strdup(filename);
 
-    result->module = module;
-    result->instance = instance;
+    /**
+     * L'instance Python et l'objet GLib résultante sont un même PyGObject.
+     *
+     * Donc pas besoin de toucher au comptage des références ici, la libération
+     * se réalisera à la fin, quand l'objet GLib sera libéré.
+     */
 
-    Py_INCREF(instance);
+    Py_DECREF(module);
 
     return G_PLUGIN_MODULE(result);
 
diff --git a/plugins/pychrysalide/pychrysa.c b/plugins/pychrysalide/pychrysa.c
index 4cb18d9..3e14add 100644
--- a/plugins/pychrysalide/pychrysa.c
+++ b/plugins/pychrysalide/pychrysa.c
@@ -306,13 +306,22 @@ static bool set_version_for_gtk_namespace(const char *version)
 
 static void PyExit_pychrysalide(void)
 {
+    assert(_standalone);
+
     extern void set_current_project(void *project);
 
     set_current_project(NULL);
 
 #ifdef TRACK_GOBJECT_LEAKS
-    if (_standalone)
-        dump_remaining_gtypes();
+    remember_gtypes_for_leaks();
+#endif
+
+    exit_all_plugins();
+
+    unload_all_basic_components();
+
+#ifdef TRACK_GOBJECT_LEAKS
+    dump_remaining_gtypes();
 #endif
 
 }
@@ -500,7 +509,12 @@ PyMODINIT_FUNC PyInit_pychrysalide(void)
 
         load_remaning_plugins();
 
-        g_object_unref(G_OBJECT(self));
+        /**
+         * On laisse fuir ici la référence sur self afin d'avoir
+         * l'assurance que le greffon se déchargera toujours en dernier.
+         *
+         * La fuite mémoire est au final évitée dans PyExit_pychrysalide().
+         */
 
     }
 
@@ -657,6 +671,8 @@ static void load_python_plugins(GPluginModule *plugin)
 
     }
 
+    free(paths);
+
 }
 
 
@@ -737,6 +753,8 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
 
 G_MODULE_EXPORT void chrysalide_plugin_exit(GPluginModule *plugin)
 {
+    clear_all_accesses_to_python_modules();
+
     Py_XDECREF(_chrysalide_module);
 
 }
diff --git a/src/analysis/db/collection.c b/src/analysis/db/collection.c
index 9c28c4a..0a617f3 100644
--- a/src/analysis/db/collection.c
+++ b/src/analysis/db/collection.c
@@ -149,6 +149,18 @@ static void g_db_collection_init(GDbCollection *collec)
 
 static void g_db_collection_dispose(GDbCollection *collec)
 {
+    if (collec->items != NULL)
+    {
+        g_list_free_full(collec->items, g_object_unref);
+        collec->items = NULL;
+    }
+
+    if (collec->sorted != NULL)
+    {
+        g_list_free_full(collec->sorted, g_object_unref);
+        collec->sorted = NULL;
+    }
+
     G_OBJECT_CLASS(g_db_collection_parent_class)->dispose(G_OBJECT(collec));
 
 }
@@ -1130,6 +1142,8 @@ bool g_db_collection_load_all_items(GDbCollection *collec, sqlite3 *db)
         result = g_db_item_load(new, values, count);
         result &= g_db_collection_add_item(G_DB_COLLECTION(collec), new);
 
+        g_object_unref(G_OBJECT(new));
+
     }
 
     /* Sortie propre */
diff --git a/src/analysis/project.c b/src/analysis/project.c
index 6156fbc..57ebcc6 100644
--- a/src/analysis/project.c
+++ b/src/analysis/project.c
@@ -1345,6 +1345,9 @@ static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid,
 
                 }
 
+                if (handler->filter != NULL)
+                    handler->filter(NULL, handler->data);
+
             }
 
             else
diff --git a/src/analysis/routine.c b/src/analysis/routine.c
index 8b49456..d206e5e 100644
--- a/src/analysis/routine.c
+++ b/src/analysis/routine.c
@@ -539,12 +539,8 @@ GDataType *g_binary_routine_get_return_type(const GBinRoutine *routine)
 
 void g_binary_routine_add_arg(GBinRoutine *routine, GBinVariable *var)
 {
-    routine->args_count++;
+    routine->args = realloc(routine->args, ++routine->args_count * sizeof(GBinVariable *));
 
-    routine->args = (GBinVariable **)realloc(routine->args,
-                                             routine->args_count * sizeof(GBinVariable *));
-
-    g_object_ref(G_OBJECT(var));
     routine->args[routine->args_count - 1] = var;
 
 }
diff --git a/src/gleak.c b/src/gleak.c
index 3212d9f..4423cbb 100644
--- a/src/gleak.c
+++ b/src/gleak.c
@@ -24,10 +24,12 @@
 #include "gleak.h"
 
 
+#include <assert.h>
 #include <glib-object.h>
 #include <malloc.h>
 #include <stdbool.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 
@@ -39,12 +41,122 @@
 #define DUMP_CLOSE_MSG "\n----------------------------------------------\n\n"
 
 
+/* Description de type utilisé */
+typedef struct _tracked_gtype_t
+{
+    GType type;                             /* Type GLib représenté        */
+    char *name;                             /* Désignation humaine         */
+
+} tracked_gtype_t;
+
+/* Conservation des types même sans les greffons associés */
+static tracked_gtype_t *__tracking = NULL;
+static size_t __count = 0;
+
+
+/* Effectue une comparaison entre deux mémorisations de GTypes. */
+static int compare_gtypes_for_leaks(const tracked_gtype_t *, const tracked_gtype_t *);
+
+/* Constitue une base de données de nom de tous les GTypes. */
+static void _remember_gtypes_for_leaks(GType);
 
 /*  Parcourt l'arborescence des types à la recherche de fuites. */
 static void track_gtype_for_leak(GType, bool *);
 
 
 
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : a = première description à comparer.                         *
+*                b = seconde description à comparer.                          *
+*                                                                             *
+*  Description : Effectue une comparaison entre deux mémorisations de GTypes. *
+*                                                                             *
+*  Retour      : Bilan de l'opération (-1, 0 ou 1).                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static int compare_gtypes_for_leaks(const tracked_gtype_t *a, const tracked_gtype_t *b)
+{
+    int result;                             /* Bilan à retourner           */
+
+    if (a->type < b->type)
+        result = -1;
+
+    else if (a->type > b->type)
+        result = 1;
+
+    else
+        result = 0;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : root  = racine des types d'instance à parcourir.             *
+*                                                                             *
+*  Description : Constitue une base de données de nom de tous les GTypes.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void _remember_gtypes_for_leaks(GType root)
+{
+    GType *children;                        /* Liste de tous les sous-types*/
+    guint count;                            /* Taille de cette liste       */
+    tracked_gtype_t *new;                   /* Nouvelle feuille à mémoriser*/
+    GType *iter;                            /* Boucle de parcours          */
+
+    children = g_type_children(root, &count);
+
+    if (count == 0)
+    {
+        __tracking = realloc(__tracking, ++__count * sizeof(tracked_gtype_t));
+
+        new = &__tracking[__count - 1];
+
+        new->type = root;
+        new->name = strdup(g_type_name(root));
+
+    }
+
+    else
+        for (iter = children; *iter != 0; iter++)
+            _remember_gtypes_for_leaks(*iter);
+
+    g_free(children);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : root  = racine des types d'instance à parcourir.             *
+*                                                                             *
+*  Description : Constitue une base de données de nom de tous les GTypes.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void remember_gtypes_for_leaks(void)
+{
+    _remember_gtypes_for_leaks(G_TYPE_OBJECT);
+
+}
+
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : root  = racine des types d'instance à retrouver.             *
@@ -62,8 +174,9 @@ static void track_gtype_for_leak(GType root, bool *first)
 {
     GType *children;                        /* Liste de tous les sous-types*/
     guint count;                            /* Taille de cette liste       */
-    GType *iter;                            /* Boucle de parcours          */
     int remaining;                          /* Nombre d'instances restantes*/
+    const tracked_gtype_t *tracked;         /* Infos de type mémorisées    */
+    GType *iter;                            /* Boucle de parcours          */
 
     children = g_type_children(root, &count);
 
@@ -79,7 +192,12 @@ static void track_gtype_for_leak(GType root, bool *first)
                 *first = false;
             }
 
-            fprintf(stderr, "%s: %d\n", g_type_name(root), remaining);
+            tracked = bsearch((tracked_gtype_t []) { { .type = root } }, __tracking,
+                              __count, sizeof(tracked_gtype_t), (__compar_fn_t)compare_gtypes_for_leaks);
+
+            assert(tracked != NULL);
+
+            fprintf(stderr, "%s: %d\n", tracked->name, remaining);
 
         }
 
@@ -110,6 +228,7 @@ void dump_remaining_gtypes(void)
 {
     char *debug;                            /* Conditions d'environnement  */
     bool first;                             /* Première fois ?             */
+    size_t i;                               /* Boucle de parcours          */
 
     debug = get_env_var("GOBJECT_DEBUG");
 
@@ -125,6 +244,8 @@ void dump_remaining_gtypes(void)
     {
         first = true;
 
+        qsort(__tracking, __count, sizeof(tracked_gtype_t), (__compar_fn_t)compare_gtypes_for_leaks);
+
         track_gtype_for_leak(G_TYPE_OBJECT, &first);
 
         if (!first)
@@ -134,4 +255,16 @@ void dump_remaining_gtypes(void)
 
     free(debug);
 
+    for (i = 0; i < __count; i++)
+        free(__tracking[i].name);
+
+    if (__tracking != NULL)
+    {
+        free(__tracking);
+
+        __tracking = NULL;
+        __count = 0;
+
+    }
+
 }
diff --git a/src/gleak.h b/src/gleak.h
index 233fabb..f80e167 100644
--- a/src/gleak.h
+++ b/src/gleak.h
@@ -25,6 +25,8 @@
 #define _GLEAK_H
 
 
+/* Constitue une base de données de nom de tous les GTypes. */
+void remember_gtypes_for_leaks(void);
 
 /* Affiche la liste des instances courantes restantes par type. */
 void dump_remaining_gtypes(void);
diff --git a/src/main.c b/src/main.c
index ef0335a..e5a964e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -404,6 +404,10 @@ int main(int argc, char **argv)
 
  exit_complete_gui:
 
+#ifdef TRACK_GOBJECT_LEAKS
+    remember_gtypes_for_leaks();
+#endif
+
     exit_all_plugins();
 
     if (!batch_mode)
diff --git a/src/plugins/plugin-def.h b/src/plugins/plugin-def.h
index 6d4253e..3717035 100644
--- a/src/plugins/plugin-def.h
+++ b/src/plugins/plugin-def.h
@@ -223,14 +223,22 @@ typedef struct _plugin_interface
     uint64_t magic;                         /* Vérification a minima       */
     plugin_abi_version_t abi_version;       /* Version du protocole utilisé*/
 
-    const char *gtp_name;                   /* Désignation du GType associé*/
-    const char *name;                       /* Désignation humaine courte  */
-    const char *desc;                       /* Description plus loquace    */
-    const char *version;                    /* Version du greffon          */
+    /**
+     * Les champs suivants ne sont généralement pas alloués dynamiquement,
+     * car issus des données des greffons natifs.
+     *
+     * Dans le cas des autres types d'extensions (par exemple ceux en Python),
+     * les éléments sont construits à la volée, donc à libérer après usage.
+     */
+
+    char *gtp_name;                         /* Désignation du GType associé*/
+    char *name;                             /* Désignation humaine courte  */
+    char *desc;                             /* Description plus loquace    */
+    char *version;                          /* Version du greffon          */
 
     bool container;                         /* Mise en place de greffons ? */
 
-    const char **required;                  /* Pré-chargements requis      */
+    char **required;                        /* Pré-chargements requis      */
     size_t required_count;                  /* Quantité de ces dépendances */
 
     plugin_action_t *actions;               /* Liste des actions gérées    */
@@ -251,7 +259,7 @@ typedef struct _plugin_interface
 
 #define AL(...) BUILD_PG_LIST(.actions, ((plugin_action_t []){ __VA_ARGS__ }))
 
-#define RL(...) BUILD_PG_LIST(.required, ((const char *[]){ __VA_ARGS__ }))
+#define RL(...) BUILD_PG_LIST(.required, ((char *[]){ __VA_ARGS__ }))
 
 #define NO_REQ EMPTY_PG_LIST(.required)
 
-- 
cgit v0.11.2-87-g4458