From 17f591f2230ac66394467d5e5eefe71cb259637d Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Tue, 5 Feb 2019 23:03:38 +0100
Subject: Fixed a huge number of memory leaks.

---
 configure.ac                         |  2 +-
 plugins/arm/context.c                |  5 +-
 plugins/dwarf/format.c               |  3 +-
 plugins/elf/format.c                 |  2 +
 plugins/elf/loading.c                |  2 +
 plugins/elf/strings.c                |  8 +++
 plugins/elf/symbols.c                |  9 +++-
 plugins/lnxsyscalls/hops_armv7.c     |  5 ++
 plugins/pychrysalide/format/format.c |  3 ++
 plugins/readelf/strtab.c             |  8 +++
 src/analysis/block-int.h             |  1 +
 src/analysis/block.c                 |  3 --
 src/analysis/db/collection-int.h     |  1 +
 src/analysis/db/collection.c         |  2 -
 src/analysis/db/items/comment.c      | 10 ++--
 src/analysis/disass/area.c           |  6 ++-
 src/analysis/disass/block.c          | 12 ++---
 src/analysis/disass/links.c          |  1 +
 src/analysis/loading.c               | 23 +++++----
 src/analysis/project.c               | 62 ++++++++++++-----------
 src/analysis/routine.c               | 95 +++++++++++++++++++++++++++++++++++-
 src/arch/context.c                   | 11 ++++-
 src/arch/instruction.c               | 21 +++-----
 src/arch/link.c                      |  1 -
 src/arch/processor.c                 | 16 +++++-
 src/arch/target.c                    | 11 ++---
 src/common/xml.c                     |  2 +
 src/format/debuggable.c              |  2 -
 src/format/executable.c              |  3 +-
 src/format/format.c                  | 26 ++++++++--
 src/format/strsym.c                  |  2 +-
 src/glibext/gbinportion.c            |  8 +++
 src/gui/editor.c                     | 30 ++++--------
 33 files changed, 276 insertions(+), 120 deletions(-)

diff --git a/configure.ac b/configure.ac
index 4e2967e..3043e7e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -349,7 +349,7 @@ AC_SUBST(LIBPYGOBJECT_LIBS)
 
 AC_CONFIG_FILES([stamp-h po/Makefile.in], [echo timestamp > stamp-h])
 
-AC_CONFIG_COMMANDS([marshal], [echo -e "VOID:UINT64\nVOID:INT,UINT64,INT\nVOID:OBJECT,OBJECT\nVOID:ENUM,OBJECT\nVOID:ENUM,ENUM\nVOID:BOOLEAN,UINT64\nVOID:BOOLEAN,ULONG,ULONG\nVOID:INT,INT\nVOID:OBJECT,BOOLEAN\nVOID:ULONG,BOOLEAN\nVOID:POINTER,UINT" > src/glibext/chrysamarshal.list])
+AC_CONFIG_COMMANDS([marshal], [echo -e "VOID:UINT64\nVOID:INT,UINT64,INT\nVOID:OBJECT,OBJECT\nVOID:ENUM,OBJECT\nVOID:ENUM,ENUM\nVOID:BOOLEAN,UINT64\nVOID:BOOLEAN,ULONG,ULONG\nVOID:INT,INT\nVOID:OBJECT,BOOLEAN\nVOID:ULONG,BOOLEAN" > src/glibext/chrysamarshal.list])
 
 AC_CONFIG_FILES([Makefile
                  doc/Makefile
diff --git a/plugins/arm/context.c b/plugins/arm/context.c
index 6b62760..8f6ab52 100644
--- a/plugins/arm/context.c
+++ b/plugins/arm/context.c
@@ -140,6 +140,9 @@ static void g_arm_context_dispose(GArmContext *ctx)
 
 static void g_arm_context_finalize(GArmContext *ctx)
 {
+    if (ctx->areas != NULL)
+        free(ctx->areas);
+
     G_OBJECT_CLASS(g_arm_context_parent_class)->finalize(G_OBJECT(ctx));
 
 }
@@ -240,7 +243,7 @@ void _g_arm_context_define_encoding(GArmContext *ctx, virt_t addr, unsigned int
     /* Sinon on redivise... */
     else
     {
-        ctx->areas = (disass_arm_area *)realloc(ctx->areas, ++ctx->acount * sizeof(disass_arm_area));
+        ctx->areas = realloc(ctx->areas, ++ctx->acount * sizeof(disass_arm_area));
 
         memmove(&ctx->areas[selected + 1], &ctx->areas[selected],
                 (ctx->acount - selected - 1) * sizeof(disass_arm_area));
diff --git a/plugins/dwarf/format.c b/plugins/dwarf/format.c
index 96ce831..e071f1c 100644
--- a/plugins/dwarf/format.c
+++ b/plugins/dwarf/format.c
@@ -216,8 +216,7 @@ GDbgFormat *g_dwarf_format_new(GExeFormat *parent)
 
     result = g_object_new(G_TYPE_DWARF_FORMAT, NULL);
 
-    G_DBG_FORMAT(result)->executable = parent;
-    g_object_ref(G_OBJECT(parent));
+    g_debuggable_format_attach_executable(G_DBG_FORMAT(result), parent);
 
     content = G_BIN_FORMAT(parent)->content;
 
diff --git a/plugins/elf/format.c b/plugins/elf/format.c
index d6bdc5e..08472e4 100644
--- a/plugins/elf/format.c
+++ b/plugins/elf/format.c
@@ -541,6 +541,8 @@ static bool g_elf_format_get_main_address(GElfFormat *format, vmpa2t *addr)
 
         copy_vmpa(addr, get_mrange_addr(range));
 
+        g_object_unref(G_OBJECT(symbol));
+
     }
 
     return result;
diff --git a/plugins/elf/loading.c b/plugins/elf/loading.c
index eb992b9..73e75f0 100644
--- a/plugins/elf/loading.c
+++ b/plugins/elf/loading.c
@@ -496,6 +496,8 @@ static void g_elf_loading_process(GElfLoading *loading, GtkStatusStack *status)
             {
                 ret = loading->callback_1(loading, format, symbol);
 
+                g_object_unref(G_OBJECT(symbol));
+
                 if (!ret)
                 {
                     log_variadic_message(LMT_ERROR, _("Error while applying ELF relocation %zu!"), processed);
diff --git a/plugins/elf/strings.c b/plugins/elf/strings.c
index f6be4a8..fe37a0d 100644
--- a/plugins/elf/strings.c
+++ b/plugins/elf/strings.c
@@ -345,6 +345,12 @@ static bool do_elf_string_loading(GElfLoading *loading, GElfFormat *format, phys
 
         g_raw_instruction_mark_as_string(G_RAW_INSTRUCTION(instr), true);
 
+        /**
+         * Comme g_preload_info_add_instruction() peut consommer l'instruction
+         * et qu'on réutilise cette dernière ensuite avec g_arch_instruction_get_range()...
+         */
+        g_object_ref(G_OBJECT(instr));
+
         inserted = g_preload_info_add_instruction(base->info, instr);
 
         result |= inserted;
@@ -373,6 +379,8 @@ static bool do_elf_string_loading(GElfLoading *loading, GElfFormat *format, phys
 
         }
 
+        g_object_unref(G_OBJECT(instr));
+
         /* Conclusion */
 
  skip_first:
diff --git a/plugins/elf/symbols.c b/plugins/elf/symbols.c
index b6f05f6..5ddc99c 100644
--- a/plugins/elf/symbols.c
+++ b/plugins/elf/symbols.c
@@ -195,7 +195,10 @@ static void register_elf_entry_point(GElfFormat *format, virt_t vaddr, phys_t le
     /* Comptabilisation en tant que symbole */
 
     if (g_binary_format_find_symbol_at(G_BIN_FORMAT(format), &addr, &symbol))
+    {
+        g_object_unref(G_OBJECT(symbol));
         g_object_unref(G_OBJECT(routine));
+    }
 
     else
     {
@@ -552,11 +555,13 @@ static bool do_elf_symbol_loading(GElfLoading *loading, GElfFormat *format, bool
     {
         g_binary_symbol_set_status(symbol, status);
 
+        /*
         if (new != NULL)
         {
             g_object_ref(G_OBJECT(symbol));
             *new = symbol;
         }
+        */
 
         g_binary_format_add_symbol(base, symbol);
 
@@ -749,6 +754,8 @@ static bool do_elf_global_symbol_loading(GElfLoading *loading, GElfFormat *forma
 
     result = do_elf_symbol_loading(loading, format, false, iter, &symbol);
 
+    //g_clear_object(&symbol);
+
     return result;
 
 }
@@ -1048,7 +1055,7 @@ static bool load_elf_relocations(GElfFormat *format, const elf_phdr *dynamic, el
     {
         result &= g_elf_loading_get_status(loadings[i]);
 
-        g_object_ref(G_OBJECT(loadings[i]));
+        g_object_unref(G_OBJECT(loadings[i]));
 
     }
 
diff --git a/plugins/lnxsyscalls/hops_armv7.c b/plugins/lnxsyscalls/hops_armv7.c
index d706a10..cde092c 100644
--- a/plugins/lnxsyscalls/hops_armv7.c
+++ b/plugins/lnxsyscalls/hops_armv7.c
@@ -148,11 +148,16 @@ static bool resolve_armv7_linux_syscall_number(tracked_path *exec, GArchProcesso
         op = g_arch_instruction_get_operand(instr, 1);
 
         if (!G_IS_IMM_OPERAND(op))
+        {
+            g_object_unref(G_OBJECT(op));
             goto ralsn_exit;
+        }
 
         *nr = g_imm_operand_get_raw_value(G_IMM_OPERAND(op));
         result = true;
 
+        g_object_unref(G_OBJECT(op));
+
     }
 
  ralsn_exit:
diff --git a/plugins/pychrysalide/format/format.c b/plugins/pychrysalide/format/format.c
index e285116..82cb575 100644
--- a/plugins/pychrysalide/format/format.c
+++ b/plugins/pychrysalide/format/format.c
@@ -243,7 +243,10 @@ static PyObject *py_binary_format_find_symbol_by_label(PyObject *self, PyObject
     found = g_binary_format_find_symbol_by_label(format, PyUnicode_DATA(label), &symbol);
 
     if (found)
+    {
         result = pygobject_new(G_OBJECT(symbol));
+        g_object_unref(G_OBJECT(symbol));
+    }
     else
     {
         result = Py_None;
diff --git a/plugins/readelf/strtab.c b/plugins/readelf/strtab.c
index 7645dec..277d391 100644
--- a/plugins/readelf/strtab.c
+++ b/plugins/readelf/strtab.c
@@ -106,6 +106,12 @@ static void parse_elf_string_table(GElfFormat *format, GPreloadInfo *info, const
 
             g_raw_instruction_mark_as_string(G_RAW_INSTRUCTION(instr), true);
 
+            /**
+             * Comme g_preload_info_add_instruction() peut consommer l'instruction
+             * et qu'on réutilise cette dernière ensuite avec g_arch_instruction_get_range()...
+             */
+            g_object_ref(G_OBJECT(instr));
+
             inserted = g_preload_info_add_instruction(info, instr);
 
             if (inserted)
@@ -127,6 +133,8 @@ static void parse_elf_string_table(GElfFormat *format, GPreloadInfo *info, const
 
             }
 
+            g_object_unref(G_OBJECT(instr));
+
             /* Conclusion */
 
             cut = (data[end - 1] == '\0');
diff --git a/src/analysis/block-int.h b/src/analysis/block-int.h
index 8f97794..6759e7b 100644
--- a/src/analysis/block-int.h
+++ b/src/analysis/block-int.h
@@ -53,6 +53,7 @@ struct _GCodeBlock
 {
     GObject parent;                         /* A laisser en premier        */
 
+    /* Référence circulaire */
     GBlockList *list;                       /* Lien vers l'ensemble        */
 
     bitfield_t *domination;                 /* Blocs dominés de l'ensemble */
diff --git a/src/analysis/block.c b/src/analysis/block.c
index 9708ef4..a7172af 100644
--- a/src/analysis/block.c
+++ b/src/analysis/block.c
@@ -158,8 +158,6 @@ static void g_code_block_init(GCodeBlock *block)
 
 static void g_code_block_dispose(GCodeBlock *block)
 {
-    g_clear_object(&block->list);
-
     g_clear_object(&block->view);
 
     G_OBJECT_CLASS(g_code_block_parent_class)->dispose(G_OBJECT(block));
@@ -666,7 +664,6 @@ void g_block_list_add_block(GBlockList *list, GCodeBlock *block, size_t index)
     list->blocks[index] = block;
 
     block->list = list;
-    g_object_ref(G_OBJECT(list));
 
     g_code_block_set_index(block, index);
 
diff --git a/src/analysis/db/collection-int.h b/src/analysis/db/collection-int.h
index cb0aea6..c2d1282 100644
--- a/src/analysis/db/collection-int.h
+++ b/src/analysis/db/collection-int.h
@@ -55,6 +55,7 @@ struct _GDbCollection
     GType type;                             /* Identifiant GLib équivalent */
     const char *name;                       /* Nom en base de données      */
 
+    /* Référence circulaire */
     GLoadedBinary *binary;                  /* Binaire rattaché éventuel   */
 
     GList *items;                           /* Eléments rassemblés         */
diff --git a/src/analysis/db/collection.c b/src/analysis/db/collection.c
index 0e4f756..9c28c4a 100644
--- a/src/analysis/db/collection.c
+++ b/src/analysis/db/collection.c
@@ -219,8 +219,6 @@ GDbCollection *g_db_collection_new(uint32_t id, GType type, const char *name)
 
 void g_db_collection_link_to_binary(GDbCollection *collec, GLoadedBinary *binary)
 {
-    g_object_ref(G_OBJECT(binary));
-
     collec->binary = binary;
 
 }
diff --git a/src/analysis/db/items/comment.c b/src/analysis/db/items/comment.c
index b879d08..7eb7906 100644
--- a/src/analysis/db/items/comment.c
+++ b/src/analysis/db/items/comment.c
@@ -301,11 +301,10 @@ static void g_db_comment_dispose(GDbComment *comment)
 {
     size_t i;                               /* Boucle de parcours          */
 
-    for (i = 0; i < comment->old_count; i++)
-        g_object_unref(G_OBJECT(comment->old_inlined[i]));
+    g_clear_object(&comment->previous);
 
-    if (comment->old_inlined != NULL)
-        free(comment->old_inlined);
+    for (i = 0; i < comment->old_count; i++)
+        g_clear_object(&comment->old_inlined[i]);
 
     G_OBJECT_CLASS(g_db_comment_parent_class)->dispose(G_OBJECT(comment));
 
@@ -346,6 +345,9 @@ static void g_db_comment_finalize(GDbComment *comment)
 
     unlock_flat_array(&comment->text);
 
+    if (comment->old_inlined != NULL)
+        free(comment->old_inlined);
+
     G_OBJECT_CLASS(g_db_comment_parent_class)->finalize(G_OBJECT(comment));
 
 }
diff --git a/src/analysis/disass/area.c b/src/analysis/disass/area.c
index 84bf8a4..f1aa002 100644
--- a/src/analysis/disass/area.c
+++ b/src/analysis/disass/area.c
@@ -348,8 +348,7 @@ static void fini_mem_area(mem_area *area)
     len = get_mrange_length(&area->range);
 
     for (i = 0; i < len; i++)
-        if (area->instructions[i] != NULL)
-            g_object_unref(G_OBJECT(area->instructions[i]));
+        g_clear_object(&area->instructions[i]);
 
     free(area->instructions);
 
@@ -681,7 +680,10 @@ static void update_address_as_routine(GBinFormat *format, const vmpa2t *addr)
     if (!found || (found && wrong_type))
     {
         if (found)
+        {
             g_binary_format_remove_symbol(format, symbol);
+            g_object_unref(G_OBJECT(symbol));
+        }
 
         init_mrange(&range, addr, 0);
 
diff --git a/src/analysis/disass/block.c b/src/analysis/disass/block.c
index 021284e..9fce202 100644
--- a/src/analysis/disass/block.c
+++ b/src/analysis/disass/block.c
@@ -41,6 +41,7 @@ struct _GBasicBlock
 {
     GCodeBlock parent;                      /* A laisser en premier        */
 
+    /* Référence circulaire */
     GLoadedBinary *binary;                  /* Binaire chargé et associé   */
 
     GArchInstruction *first;                /* Première instruction        */
@@ -159,10 +160,8 @@ static void g_basic_block_init(GBasicBlock *block)
 
 static void g_basic_block_dispose(GBasicBlock *block)
 {
-    g_clear_object(&block->binary);
-
-    g_clear_object(&block->first);
-    g_clear_object(&block->last);
+    //g_clear_object(&block->first);
+    //g_clear_object(&block->last);
 
     G_OBJECT_CLASS(g_basic_block_parent_class)->dispose(G_OBJECT(block));
 
@@ -211,13 +210,12 @@ GCodeBlock *g_basic_block_new(GLoadedBinary *binary, GArchInstruction *first, GA
     result = g_object_new(G_TYPE_BASIC_BLOCK, NULL);
 
     result->binary = binary;
-    g_object_ref(G_OBJECT(binary));
 
     result->first = first;
     result->last = last;
 
-    g_object_ref(G_OBJECT(first));
-    g_object_ref(G_OBJECT(last));
+    //g_object_ref(G_OBJECT(first));
+    //g_object_ref(G_OBJECT(last));
 
     parent = G_CODE_BLOCK(result);
 
diff --git a/src/analysis/disass/links.c b/src/analysis/disass/links.c
index 381aedc..26788db 100644
--- a/src/analysis/disass/links.c
+++ b/src/analysis/disass/links.c
@@ -128,6 +128,7 @@ void establish_natural_link(GArchInstruction *instr, GArchInstruction *prev)
                 else
                 {
                     no_need = true;
+                    unref_instr_link(other);
                     goto check_done;
                 }
                 break;
diff --git a/src/analysis/loading.c b/src/analysis/loading.c
index 0ded268..664b8d6 100644
--- a/src/analysis/loading.c
+++ b/src/analysis/loading.c
@@ -782,6 +782,8 @@ void g_content_explorer_delete_group(GContentExplorer *explorer, wgroup_id_t wid
 
     g_work_queue_delete_work_group(queue, group->wid);
 
+    g_object_unref(G_OBJECT(group->original));
+
     for (i = 0; i < group->count; i++)
         g_object_unref(G_OBJECT(group->contents[i]));
 
@@ -802,8 +804,7 @@ void g_content_explorer_delete_group(GContentExplorer *explorer, wgroup_id_t wid
         memmove(&explorer->groups[index], &explorer->groups[index + 1],
                 (explorer->count - index - 1) * sizeof(exploring_group));
 
-    explorer->groups = (exploring_group *)realloc(explorer->groups,
-                                                  --explorer->count * sizeof(exploring_group));
+    explorer->groups = realloc(explorer->groups, --explorer->count * sizeof(exploring_group));
 
     /* Sortie */
 
@@ -839,7 +840,7 @@ void g_content_explorer_populate_group(GContentExplorer *explorer, wgroup_id_t w
 
     /* Conservation du résultat */
 
-    group->contents = (GBinContent **)realloc(group->contents, ++group->count * sizeof(GBinContent *));
+    group->contents = realloc(group->contents, ++group->count * sizeof(GBinContent *));
 
     group->contents[group->count - 1] = content;
     g_object_ref(G_OBJECT(content));
@@ -885,7 +886,7 @@ void g_content_explorer_note_detected(GContentExplorer *explorer, wgroup_id_t wi
     group = g_content_explorer_find_group(explorer, wid);
     assert(group != NULL);
 
-    group->loaded = (GLoadedContent **)realloc(group->loaded, ++group->noted * sizeof(GLoadedContent *));
+    group->loaded = realloc(group->loaded, ++group->noted * sizeof(GLoadedContent *));
 
     group->loaded[group->noted - 1] = loaded;
     g_object_ref(G_OBJECT(loaded));
@@ -923,7 +924,7 @@ GBinContent **g_content_explorer_get_all(GContentExplorer *explorer, wgroup_id_t
     /* Allocation de la liste finale */
 
     *count = 1 + group->count;
-    result = (GBinContent **)malloc(*count * sizeof(GBinContent *));
+    result = malloc(*count * sizeof(GBinContent *));
 
     /* On regarde déjà du côté de la source */
 
@@ -1438,7 +1439,7 @@ void g_content_resolver_create_group(GContentResolver *resolver, wgroup_id_t wid
     if (noted > 0)
     {
         group->count = noted;
-        group->loaded = (GLoadedContent **)realloc(group->loaded, group->count * sizeof(GLoadedContent *));
+        group->loaded = realloc(group->loaded, group->count * sizeof(GLoadedContent *));
 
         for (i = 0; i < noted; i++)
         {
@@ -1496,6 +1497,9 @@ void g_content_resolver_delete_group(GContentResolver *resolver, wgroup_id_t wid
     for (i = 0; i < group->count; i++)
         g_object_unref(G_OBJECT(group->loaded[i]));
 
+    if (group->loaded != NULL)
+        free(group->loaded);
+
     /* Réorganisation de la liste */
 
     index = group - resolver->groups;
@@ -1504,8 +1508,7 @@ void g_content_resolver_delete_group(GContentResolver *resolver, wgroup_id_t wid
         memmove(&resolver->groups[index], &resolver->groups[index + 1],
                 (resolver->count - index - 1) * sizeof(resolving_group));
 
-    resolver->groups = (resolving_group *)realloc(resolver->groups,
-                                                  --resolver->count * sizeof(resolving_group));
+    resolver->groups = realloc(resolver->groups, --resolver->count * sizeof(resolving_group));
 
     /* Sortie */
 
@@ -1537,7 +1540,7 @@ void g_content_resolver_add_detected(GContentResolver *resolver, wgroup_id_t wid
     group = g_content_resolver_find_group(resolver, wid);
     assert(group != NULL);
 
-    group->loaded = (GLoadedContent **)realloc(group->loaded, ++group->count * sizeof(GLoadedContent *));
+    group->loaded = realloc(group->loaded, ++group->count * sizeof(GLoadedContent *));
 
     group->loaded[group->count - 1] = loaded;
     g_object_ref(G_OBJECT(loaded));
@@ -1575,7 +1578,7 @@ GLoadedContent **g_content_resolver_get_all(GContentResolver *resolver, wgroup_i
     /* Allocation de la liste finale */
 
     *count = group->count;
-    result = (GLoadedContent **)malloc(*count * sizeof(GLoadedContent *));
+    result = malloc(*count * sizeof(GLoadedContent *));
 
     /* On parcourt les éventuels contenus encapsulés découverts */
 
diff --git a/src/analysis/project.c b/src/analysis/project.c
index 4574d88..6156fbc 100644
--- a/src/analysis/project.c
+++ b/src/analysis/project.c
@@ -67,7 +67,7 @@ struct _GStudyProjectClass
 
     /* Signaux */
 
-    void (* contents_available) (GStudyProject, GLoadedContent **, guint);
+    void (* contents_available) (GStudyProject, GLoadedContent *);
     void (* content_added) (GStudyProject *, GLoadedContent *);
     void (* content_removed) (GStudyProject *, GLoadedContent *);
 
@@ -202,13 +202,13 @@ static void g_study_project_class_init(GStudyProjectClass *klass)
     object->dispose = (GObjectFinalizeFunc/* ! */)g_study_project_dispose;
     object->finalize = (GObjectFinalizeFunc)g_study_project_finalize;
 
-    g_signal_new("contents-available",
+    g_signal_new("content-available",
                  G_TYPE_STUDY_PROJECT,
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET(GStudyProjectClass, contents_available),
                  NULL, NULL,
-                 g_cclosure_user_marshal_VOID__POINTER_UINT,
-                 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT);
+                 g_cclosure_marshal_VOID__OBJECT,
+                 G_TYPE_NONE, 1, G_TYPE_OBJECT);
 
     g_signal_new("content-added",
                  G_TYPE_STUDY_PROJECT,
@@ -610,7 +610,14 @@ void on_loaded_content_analyzed(GLoadedContent *content, gboolean success, GStud
     else
         log_variadic_message(LMT_ERROR, _("Failed to load '%s'"), desc);
 
-    g_object_ref(G_OBJECT(content));
+    /**
+     * Le contenu a normalement été sur-référencé pour ne pas disparaître
+     * en cours d'analyse.
+     *
+     * On revient donc à une situation nominale ici.
+     */
+
+    g_object_unref(G_OBJECT(content));
 
 }
 
@@ -655,8 +662,7 @@ void g_study_project_attach_content(GStudyProject *project, GLoadedContent *cont
 {
     g_study_project_lock_contents(project);
 
-    project->contents = (GLoadedContent **)realloc(project->contents,
-                                                   ++project->count * sizeof(GLoadedContent *));
+    project->contents = realloc(project->contents, ++project->count * sizeof(GLoadedContent *));
 
     project->contents[project->count - 1] = content;
     g_object_ref(G_OBJECT(content));
@@ -1208,12 +1214,12 @@ static void on_new_content_explored(GContentExplorer *explorer, wgroup_id_t wid,
         g_object_unref(G_OBJECT(resolver));
 
         for (i = 0; i < count; i++)
-           g_object_unref(G_OBJECT(available[i]));
+            g_object_unref(G_OBJECT(available[i]));
 
         free(available);
 
         for (i = 0; i < noted; i++)
-           g_object_unref(G_OBJECT(detected[i]));
+            g_object_unref(G_OBJECT(detected[i]));
 
         if (detected != NULL)
             free(detected);
@@ -1241,7 +1247,6 @@ static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid,
 {
     GLoadedContent **available;             /* Contenus chargés valables   */
     size_t count;                           /* Quantité de ces contenus    */
-    bool keep;                              /* Conservation finale de liste*/
     size_t i;                               /* Boucle de parcours          */
     GBinContent *content;                   /* Contenu brut à manipuler    */
     const gchar *hash;                      /* Empreinte d'un contenu      */
@@ -1254,8 +1259,6 @@ static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid,
     {
         available = g_content_resolver_get_all(resolver, wid, &count);
 
-        keep = false;
-
         /* Rechargement à partir d'XML ? */
         if (handler->xdoc != NULL)
         {
@@ -1316,25 +1319,21 @@ static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid,
         /* Découverte(s) initiale(s) ? */
         else
         {
-            for (i = 0; i < count; i++)
-            {
-                /**
-                 * S'il s'agit des résultats de la dernière exploration,
-                 * alors les groupes contenant les éléments chargés vont
-                 * être libéré, potentiellement pendant l'analyse.
-                 *
-                 * On temporise en incrémentant les références.
-                 */
-                g_object_ref(G_OBJECT(available[i]));
-
-            }
-
             if (is_batch_mode())
             {
                 for (i = 0; i < count; i++)
                 {
                     if (handler->filter == NULL || handler->filter(available[i], handler->data))
                     {
+                        /**
+                         * S'il s'agit des résultats de la dernière exploration,
+                         * alors les groupes contenant les éléments chargés vont
+                         * être libéré, potentiellement pendant l'analyse.
+                         *
+                         * On temporise en incrémentant les références.
+                         */
+                        g_object_ref(G_OBJECT(available[i]));
+
                         g_signal_connect(available[i], "analyzed",
                                          G_CALLBACK(on_loaded_content_analyzed), handler->project);
 
@@ -1349,17 +1348,16 @@ static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid,
             }
 
             else
-            {
-                g_signal_emit_by_name(handler->project, "contents-available", available, count);
-
-                keep = true;
-
-            }
+                for (i = 0; i < count; i++)
+                {
+                    g_signal_emit_by_name(handler->project, "content-available", available[i]);
+                    g_object_unref(G_OBJECT(available[i]));
+                }
 
         }
 
         /* Dans tous les cas... */
-        if (available != NULL && !keep)
+        if (available != NULL)
             free(available);
 
         /* Si c'était la dernière résolution... */
diff --git a/src/analysis/routine.c b/src/analysis/routine.c
index 4116044..8b49456 100644
--- a/src/analysis/routine.c
+++ b/src/analysis/routine.c
@@ -81,6 +81,12 @@ static void g_bin_routine_class_init(GBinRoutineClass *);
 /* Initialise une instance représentation de routine. */
 static void g_bin_routine_init(GBinRoutine *);
 
+/* Procède à la libération totale de la mémoire. */
+static void g_bin_routine_finalize(GBinRoutine *);
+
+/* Supprime toutes les références externes. */
+static void g_bin_routine_dispose(GBinRoutine *);
+
 /* Fournit une étiquette pour viser une routine. */
 static char *g_binary_routine_get_label(const GBinRoutine *);
 
@@ -104,8 +110,14 @@ G_DEFINE_TYPE(GBinRoutine, g_bin_routine, G_TYPE_BIN_SYMBOL);
 
 static void g_bin_routine_class_init(GBinRoutineClass *klass)
 {
+    GObjectClass *object;                   /* Version de base de la classe*/
     GBinSymbolClass *symbol;                /* Autre version de la classe  */
 
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_bin_routine_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_bin_routine_finalize;
+
     symbol = G_BIN_SYMBOL_CLASS(klass);
 
     symbol->get_label = (get_symbol_label_fc)g_binary_routine_get_label;
@@ -133,6 +145,86 @@ static void g_bin_routine_init(GBinRoutine *routine)
 
     g_binary_symbol_set_target_type(symbol, STP_ROUTINE);
 
+    routine->ret_type = NULL;
+
+    routine->namespace = NULL;
+    routine->ns_sep = NULL;
+    routine->name = NULL;
+    routine->full_name = NULL;
+
+    routine->args = NULL;
+    routine->args_count = 0;
+
+    routine->locals = NULL;
+    routine->locals_count = 0;
+
+    routine->blocks = NULL;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : routine = instance d'objet GLib à traiter.                   *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_bin_routine_dispose(GBinRoutine *routine)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    g_clear_object(&routine->ret_type);
+
+    g_clear_object(&routine->namespace);
+    g_clear_object(&routine->full_name);
+
+    for (i = 0; i < routine->args_count; i++)
+        g_clear_object(&routine->args[i]);
+
+    for (i = 0; i < routine->locals_count; i++)
+        g_clear_object(&routine->locals[i]);
+
+    g_clear_object(&routine->blocks);
+
+    G_OBJECT_CLASS(g_bin_routine_parent_class)->dispose(G_OBJECT(routine));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : routine = instance d'objet GLib à traiter.                   *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_bin_routine_finalize(GBinRoutine *routine)
+{
+    if (routine->ns_sep != NULL)
+        free(routine->ns_sep);
+
+    if (routine->name != NULL)
+        free(routine->name);
+
+    if (routine->args != NULL)
+        free(routine->args);
+
+    if (routine->locals != NULL)
+        free(routine->locals);
+
+    G_OBJECT_CLASS(g_bin_routine_parent_class)->finalize(G_OBJECT(routine));
+
 }
 
 
@@ -736,8 +828,7 @@ GBlockList *g_binary_routine_get_basic_blocks(const GBinRoutine *routine)
 
 void g_binary_routine_set_basic_blocks(GBinRoutine *routine, GBlockList *blocks)
 {
-    if (routine->blocks != NULL)
-        g_object_unref(G_OBJECT(routine->blocks));
+    g_clear_object(&routine->blocks);
 
     routine->blocks = blocks;
 
diff --git a/src/arch/context.c b/src/arch/context.c
index cedec33..3b78161 100644
--- a/src/arch/context.c
+++ b/src/arch/context.c
@@ -144,7 +144,7 @@ static void g_proc_context_dispose(GProcContext *ctx)
     size_t i;                               /* Boucle de parcours          */
 
     for (i = 0; i < ctx->items_count; i++)
-        g_object_unref(G_OBJECT(ctx->items[i]));
+        g_clear_object(&ctx->items[i]);
 
     g_mutex_clear(&ctx->items_mutex);
 
@@ -167,6 +167,15 @@ static void g_proc_context_dispose(GProcContext *ctx)
 
 static void g_proc_context_finalize(GProcContext *ctx)
 {
+    DisassPriorityLevel i;                   /* Boucle de parcours          */
+
+    for (i = 0; i < DPL_COUNT; i++)
+        if (ctx->drop_points[i] != NULL)
+            free(ctx->drop_points[i]);
+
+    if (ctx->extra_symbols != NULL)
+        free(ctx->extra_symbols);
+
     if (ctx->items != NULL)
         free(ctx->items);
 
diff --git a/src/arch/instruction.c b/src/arch/instruction.c
index 1d1ccaf..8e9d3d3 100644
--- a/src/arch/instruction.c
+++ b/src/arch/instruction.c
@@ -607,15 +607,11 @@ bool _g_arch_instruction_replace_operand(GArchInstruction *instr, GArchOperand *
 
     count = _g_arch_instruction_count_operands(instr);
 
-    for (i = 0; i < count; i++)
+    for (i = 0; i < count && !result; i++)
     {
         op = _g_arch_instruction_get_operand(instr, i);
 
-        if (op == old)
-        {
-            result = true;
-            break;
-        }
+        result = (op == old);
 
         g_object_unref(G_OBJECT(op));
 
@@ -623,7 +619,7 @@ bool _g_arch_instruction_replace_operand(GArchInstruction *instr, GArchOperand *
 
     if (result)
     {
-        rpl_item_in_flat_array(instr->operands, i, &new, sizeof(GArchOperand *));
+        rpl_item_in_flat_array(instr->operands, i - 1, &new, sizeof(GArchOperand *));
 
         g_object_unref(G_OBJECT(old));
 
@@ -654,24 +650,23 @@ bool _g_arch_instruction_detach_operand(GArchInstruction *instr, GArchOperand *t
     size_t i;                               /* Boucle de parcours          */
     GArchOperand *op;                       /* Opérande à manipuler        */
 
+    result = false;
+
     count = _g_arch_instruction_count_operands(instr);
 
-    for (i = 0; i < count; i++)
+    for (i = 0; i < count && !result; i++)
     {
         op = _g_arch_instruction_get_operand(instr, i);
 
-        if (op == target)
-            break;
+        result = (op == target);
 
         g_object_unref(G_OBJECT(op));
 
     }
 
-    result = (i < count);
-
     if (result)
     {
-        rem_item_from_flat_array(&instr->operands, i, sizeof(GArchOperand *));
+        rem_item_from_flat_array(&instr->operands, i - 1, sizeof(GArchOperand *));
 
         g_object_unref(G_OBJECT(target));
 
diff --git a/src/arch/link.c b/src/arch/link.c
index f09621e..7eaa1d9 100644
--- a/src/arch/link.c
+++ b/src/arch/link.c
@@ -138,7 +138,6 @@ void handle_branch_as_link(GArchInstruction *instr, GArchProcessor *proc, GProcC
 
         }
 
-        range = g_arch_instruction_get_range(instr);
         compute_mrange_end_addr(range, &next);
 
         target = g_arch_processor_find_instr_by_address(proc, &next);
diff --git a/src/arch/processor.c b/src/arch/processor.c
index 05e3206..dccd12e 100644
--- a/src/arch/processor.c
+++ b/src/arch/processor.c
@@ -190,8 +190,18 @@ static void g_arch_processor_dispose(GArchProcessor *proc)
     size_t i;                               /* Boucle de parcours          */
 
     for (i = 0; i < proc->instr_count; i++)
+    {
+        /**
+         * Pour éviter un cycle de maintien des références, on détruit tous
+         * les liens depuis l'extérieur !
+         */
+        if (proc->instructions[i] != NULL)
+            g_arch_instruction_delete_all_links(proc->instructions[i]);
+
         g_clear_object(&proc->instructions[i]);
 
+    }
+
     g_mutex_clear(&proc->mutex);
 
     g_mutex_clear(&proc->error_mutex);
@@ -230,6 +240,9 @@ static void g_arch_processor_finalize(GArchProcessor *proc)
 
     }
 
+    if (proc->coverages != NULL)
+        free(proc->coverages);
+
     G_OBJECT_CLASS(g_arch_processor_parent_class)->finalize(G_OBJECT(proc));
 
 }
@@ -974,8 +987,7 @@ static void g_arch_processor_add_new_coverage(GArchProcessor *proc, GArchInstruc
     {
         proc->cov_allocated += COV_ALLOC_BLOCK;
 
-        proc->coverages = (instr_coverage *)realloc(proc->coverages,
-                                                    proc->cov_allocated * sizeof(instr_coverage));
+        proc->coverages = realloc(proc->coverages, proc->cov_allocated * sizeof(instr_coverage));
 
     }
 
diff --git a/src/arch/target.c b/src/arch/target.c
index 64b12dd..d3bd89a 100644
--- a/src/arch/target.c
+++ b/src/arch/target.c
@@ -51,6 +51,7 @@ struct _GTargetOperand
     vmpa2t addr;                            /* Adresse de l'élément visé   */
 
     bool strict;                            /* Résolution stricte          */
+    /* Référence circulaire */
     GBinSymbol *symbol;                     /* Eventuel symbole associé    */
     phys_t diff;                            /* Position dans le symbole    */
 
@@ -206,9 +207,6 @@ static void g_target_operand_targetable_interface_init(GTargetableOperandInterfa
 
 static void g_target_operand_dispose(GTargetOperand *operand)
 {
-    if (operand->symbol != NULL)
-        g_object_unref(G_OBJECT(operand->symbol));
-
     G_OBJECT_CLASS(g_target_operand_parent_class)->dispose(G_OBJECT(operand));
 
 }
@@ -505,9 +503,6 @@ bool g_target_operand_resolve(GTargetOperand *operand, GBinFormat *format, bool
     const mrange_t *range;                  /* Couverture du symbole       */
 #endif
 
-    if (operand->symbol != NULL)
-        g_object_unref(G_OBJECT(operand->symbol));
-
     operand->strict = strict;
 
     result = g_binary_format_resolve_symbol(format, &operand->addr, strict, &operand->symbol, &operand->diff);
@@ -553,6 +548,10 @@ bool g_target_operand_resolve(GTargetOperand *operand, GBinFormat *format, bool
 
     }
 
+    /* Référence circulaire */
+    if (operand->symbol != NULL)
+        g_object_unref(operand->symbol);
+
     return result;
 
 }
diff --git a/src/common/xml.c b/src/common/xml.c
index 0bd4d86..aaed2ea 100644
--- a/src/common/xml.c
+++ b/src/common/xml.c
@@ -1037,6 +1037,8 @@ xmlNodePtr ensure_node_exist(xmlDocPtr xdoc, xmlXPathContextPtr context, const c
 
             iter = get_node_from_xpath(context, iter_path);
 
+            free(iter_path);
+
             if (iter == NULL) break;
             else last = iter;
 
diff --git a/src/format/debuggable.c b/src/format/debuggable.c
index 571163b..7020c38 100644
--- a/src/format/debuggable.c
+++ b/src/format/debuggable.c
@@ -125,6 +125,4 @@ void g_debuggable_format_attach_executable(GDbgFormat *format, GExeFormat *execu
 {
     format->executable = executable;
 
-    g_object_ref(G_OBJECT(executable));
-
 }
diff --git a/src/format/executable.c b/src/format/executable.c
index cda2e3a..00d685c 100644
--- a/src/format/executable.c
+++ b/src/format/executable.c
@@ -181,8 +181,7 @@ void g_exe_format_add_debug_info(GExeFormat *format, GDbgFormat *info)
     else
         log_variadic_message(LMT_INFO, _("Found debug information: %s"), desc);
 
-    format->debugs = (GDbgFormat **)realloc(format->debugs,
-                                            ++format->debugs_count * sizeof(GDbgFormat *));
+    format->debugs = realloc(format->debugs, ++format->debugs_count * sizeof(GDbgFormat *));
 
     format->debugs[format->debugs_count - 1] = info;
 
diff --git a/src/format/format.c b/src/format/format.c
index cd71a21..ab4864f 100644
--- a/src/format/format.c
+++ b/src/format/format.c
@@ -156,10 +156,19 @@ static void g_binary_format_init(GBinFormat *format)
 
 static void g_binary_format_dispose(GBinFormat *format)
 {
-    g_clear_object(&format->demangler);
+    size_t i;                               /* Boucle de parcours          */
+
+    g_clear_object(&format->content);
+
+    g_rw_lock_clear(&format->pt_lock);
 
     g_clear_object(&format->info);
 
+    g_clear_object(&format->demangler);
+
+    for (i = 0; i < format->sym_count; i++)
+        g_clear_object(&format->symbols[i]);
+
     g_rw_lock_clear(&format->syms_lock);
 
     g_mutex_clear(&format->error_mutex);
@@ -185,6 +194,15 @@ static void g_binary_format_finalize(GBinFormat *format)
 {
     size_t i;                               /* Boucle de parcours          */
 
+    if (format->entry_points != NULL)
+        free(format->entry_points);
+
+    if (format->extra_points != NULL)
+        free(format->extra_points);
+
+    if (format->symbols != NULL)
+        free(format->symbols);
+
     if (format->errors != NULL)
     {
         for (i = 0; i < format->error_count; i++)
@@ -386,8 +404,7 @@ void g_binary_format_register_code_point(GBinFormat *format, virt_t pt, bool ent
 
     if (entry)
     {
-        format->entry_points = (virt_t *)realloc(format->entry_points,
-                                                 ++format->ep_count * sizeof(virt_t));
+        format->entry_points = realloc(format->entry_points, ++format->ep_count * sizeof(virt_t));
 
         format->entry_points[format->ep_count - 1] = pt;
 
@@ -398,8 +415,7 @@ void g_binary_format_register_code_point(GBinFormat *format, virt_t pt, bool ent
         {
             format->xp_allocated += EXTRA_POINT_BLOCK;
 
-            format->extra_points = (virt_t *)realloc(format->extra_points,
-                                                     format->xp_allocated * sizeof(virt_t));
+            format->extra_points = realloc(format->extra_points, format->xp_allocated * sizeof(virt_t));
 
         }
 
diff --git a/src/format/strsym.c b/src/format/strsym.c
index 6feb8a1..4e8479e 100644
--- a/src/format/strsym.c
+++ b/src/format/strsym.c
@@ -193,7 +193,7 @@ static void g_string_symbol_feeder_interface_init(GProxyFeederInterface *iface)
 static void g_string_symbol_dispose(GStrSymbol *symbol)
 {
     if (symbol->has_content)
-        g_object_unref(G_OBJECT(symbol->content));
+        g_clear_object(&symbol->content);
 
     G_OBJECT_CLASS(g_string_symbol_parent_class)->dispose(G_OBJECT(symbol));
 
diff --git a/src/glibext/gbinportion.c b/src/glibext/gbinportion.c
index e020506..0074713 100644
--- a/src/glibext/gbinportion.c
+++ b/src/glibext/gbinportion.c
@@ -202,6 +202,11 @@ static void g_binary_portion_interface_init(GLineGeneratorInterface *iface)
 
 static void g_binary_portion_dispose(GBinPortion *portion)
 {
+    size_t i;                               /* Boucle de parcours          */
+
+    for (i = 0; i < portion->count; i++)
+        g_clear_object(&portion->subs[i]);
+
     G_OBJECT_CLASS(g_binary_portion_parent_class)->dispose(G_OBJECT(portion));
 
 }
@@ -238,6 +243,9 @@ static void g_binary_portion_finalize(GBinPortion *portion)
     if (portion->text != NULL)
         free(portion->text);
 
+    if (portion->subs != NULL)
+        free(portion->subs);
+
     G_OBJECT_CLASS(g_binary_portion_parent_class)->finalize(G_OBJECT(portion));
 
 }
diff --git a/src/gui/editor.c b/src/gui/editor.c
index 58dda53..627df95 100644
--- a/src/gui/editor.c
+++ b/src/gui/editor.c
@@ -131,7 +131,7 @@ static void notify_editor_project_change(GStudyProject *, bool);
 static gboolean scroll_for_the_first_time(GtkWidget *, GdkEvent *, GLoadedContent *);
 
 /* Présente une possibilité de sélection des contenus chargés. */
-static void on_editor_contents_available(GStudyProject *, GLoadedContent **, guint, void *);
+static void on_editor_content_available(GStudyProject *, GLoadedContent *, void *);
 
 /* Affiche le contenu qui vient de rejoindre un projet donné. */
 static void on_editor_loaded_content_added(GStudyProject *, GLoadedContent *, void *);
@@ -912,8 +912,8 @@ static void notify_editor_project_change(GStudyProject *project, bool new)
 
     if (new)
     {
-        g_signal_connect_to_main(project, "contents-available", G_CALLBACK(on_editor_contents_available), NULL,
-                                 g_cclosure_user_marshal_VOID__POINTER_UINT);
+        g_signal_connect_to_main(project, "content-available", G_CALLBACK(on_editor_content_available), NULL,
+                                 g_cclosure_marshal_VOID__OBJECT);
 
         g_signal_connect_to_main(project, "content-added", G_CALLBACK(on_editor_loaded_content_added), NULL,
                                  g_cclosure_marshal_VOID__OBJECT);
@@ -946,10 +946,9 @@ static void notify_editor_project_change(GStudyProject *project, bool new)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : project  = project impliqué dans l'opération.                *
-*                contents = nouveaux contenus à éventuellement charger.       *
-*                count    = taille de la liste fournie.                       *
-*                unused   = adresse non utilisée ici.                         *
+*  Paramètres  : project = project impliqué dans l'opération.                 *
+*                content = nouveau contenu à éventuellement charger.          *
+*                unused  = adresse non utilisée ici.                          *
 *                                                                             *
 *  Description : Présente une possibilité de sélection des contenus chargés.  *
 *                                                                             *
@@ -959,22 +958,13 @@ static void notify_editor_project_change(GStudyProject *project, bool new)
 *                                                                             *
 ******************************************************************************/
 
-static void on_editor_contents_available(GStudyProject *project, GLoadedContent **contents, guint count, void *unused)
+static void on_editor_content_available(GStudyProject *project, GLoadedContent *content, void *unused)
 {
-    guint i;                                /* Boucle de parcours          */
-
-    for (i = 0; i < count; i++)
-    {
-        g_signal_connect(contents[i], "analyzed", G_CALLBACK(on_loaded_content_analyzed), project);
+    g_object_ref(G_OBJECT(content));
 
-        g_loaded_content_analyze(contents[i], true);
+    g_signal_connect(content, "analyzed", G_CALLBACK(on_loaded_content_analyzed), project);
 
-        g_object_unref(G_OBJECT(contents[i]));
-
-    }
-
-    if (contents != NULL)
-        free(contents);
+    g_loaded_content_analyze(content, true);
 
 }
 
-- 
cgit v0.11.2-87-g4458