From d992b4ae5a35954d4fda460735f6dc861ae7bd26 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Tue, 19 Feb 2019 19:34:33 +0100
Subject: Ensured all natural links are well created.

---
 src/analysis/disass/links.c    | 28 +++++++---------
 tests/analysis/disass/Makefile |  5 ++-
 tests/analysis/disass/h1b.c    | 25 +++++++++++++++
 tests/analysis/disass/links.py | 72 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 112 insertions(+), 18 deletions(-)
 create mode 100644 tests/analysis/disass/h1b.c
 create mode 100644 tests/analysis/disass/links.py

diff --git a/src/analysis/disass/links.c b/src/analysis/disass/links.c
index 26788db..4eba0d7 100644
--- a/src/analysis/disass/links.c
+++ b/src/analysis/disass/links.c
@@ -58,8 +58,7 @@ void establish_natural_link(GArchInstruction *instr, GArchInstruction *prev)
     bool has_src;                           /* Présence de sources ?       */
     const instr_link_t *other;              /* Instruction diverse liée    */
     size_t i;                               /* Boucle de parcours          */
-    bool no_natural;                        /* Aucun lien naturel présent  */
-    bool no_need;                           /* Pas de besoin pour ce lien  */
+    bool need;                              /* Besoin exprimé pour ce lien */
 
     /**
      * Si rien ne vient séparer les deux instructions,
@@ -108,29 +107,26 @@ void establish_natural_link(GArchInstruction *instr, GArchInstruction *prev)
 
     count = g_arch_instruction_count_destinations(prev);
 
-    no_natural = true;
-    no_need = (count > 0);
+    need = true;
 
-    for (i = 0; i < count && no_natural; i++)
+    for (i = 0; i < count && need; i++)
     {
         other = g_arch_instruction_get_destination(prev, i);
 
         switch (other->type)
         {
             case ILT_EXEC_FLOW:
-                no_natural = false;
+                need = false;
+                break;
+
+            case ILT_JUMP:
+            case ILT_CASE_JUMP:
+                need = false;
                 break;
 
             case ILT_JUMP_IF_TRUE:
             case ILT_JUMP_IF_FALSE:
-                if (other->linked != instr)
-                    no_need = false;
-                else
-                {
-                    no_need = true;
-                    unref_instr_link(other);
-                    goto check_done;
-                }
+                need = (other->linked != instr);
                 break;
 
             default:
@@ -142,11 +138,9 @@ void establish_natural_link(GArchInstruction *instr, GArchInstruction *prev)
 
     }
 
- check_done:
-
     g_arch_instruction_unlock_dest(prev);
 
-    if (no_natural && !no_need)
+    if (need)
     {
         /* Vérification de la cohérence de l'ensemble */
 #ifndef NDEBUG
diff --git a/tests/analysis/disass/Makefile b/tests/analysis/disass/Makefile
index 17df230..8359b5c 100644
--- a/tests/analysis/disass/Makefile
+++ b/tests/analysis/disass/Makefile
@@ -1,5 +1,5 @@
 
-EXECUTABLES=hello endofname irreducible selfloop evalcommand
+EXECUTABLES=hello endofname irreducible selfloop evalcommand h1b
 
 all: $(EXECUTABLES)
 
@@ -18,5 +18,8 @@ selfloop: selfloop.c
 evalcommand: evalcommand.c
 	$(ARM_CROSS)gcc $< -o $@
 
+h1b: h1b.c
+	$(ARM_CROSS)gcc $< -o $@
+
 clean:
 	rm -f $(EXECUTABLES)
diff --git a/tests/analysis/disass/h1b.c b/tests/analysis/disass/h1b.c
new file mode 100644
index 0000000..f29033f
--- /dev/null
+++ b/tests/analysis/disass/h1b.c
@@ -0,0 +1,25 @@
+
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+    int i;
+
+    for (i = 0; i < argc; i++)
+    {
+        printf("arg[%d]: %s\n", i, argv[i]);
+
+        if (argc > 2)
+            printf("!");
+        else
+            printf("#");
+
+        printf(".");
+
+    }
+
+    printf("Hello\n");
+
+    return 0;
+
+}
diff --git a/tests/analysis/disass/links.py b/tests/analysis/disass/links.py
new file mode 100644
index 0000000..e0c9ec9
--- /dev/null
+++ b/tests/analysis/disass/links.py
@@ -0,0 +1,72 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+
+# S'assure du bon fonctionnement des blocs basiques
+
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.analysis.contents import FileContent
+from pychrysalide.analysis import LoadedBinary
+from pychrysalide.arch import ArchInstruction
+from pychrysalide.format.elf import ElfFormat
+import os
+import sys
+
+
+class TestDisassLinks(ChrysalideTestCase):
+    """TestCase for ARMv7."""
+
+    @classmethod
+    def setUpClass(cls):
+
+        super(TestDisassLinks, cls).setUpClass()
+
+        cls.log('Compile binary "h1b" if needed...')
+
+        fullname = sys.modules[cls.__module__].__file__
+        dirpath = os.path.dirname(fullname)
+
+        os.system('make -C %s h1b > /dev/null 2>&1' % dirpath)
+
+
+    @classmethod
+    def tearDownClass(cls):
+
+        super(TestDisassLinks, cls).tearDownClass()
+
+        cls.log('Delete built binaries...')
+
+        fullname = sys.modules[cls.__module__].__file__
+        dirpath = os.path.dirname(fullname)
+
+        os.system('make -C %s clean > /dev/null 2>&1' % dirpath)
+
+
+    def testNaturalLinks(self):
+        """Ensure all natural links are well created."""
+
+        fullname = sys.modules[self.__class__.__module__].__file__
+        filename = os.path.basename(fullname)
+
+        baselen = len(fullname) - len(filename)
+
+        cnt = FileContent(fullname[:baselen] + 'h1b')
+        self.assertIsNotNone(cnt)
+
+        fmt = ElfFormat(cnt)
+        self.assertIsNotNone(fmt)
+
+        binary = LoadedBinary(fmt)
+        self.assertIsNotNone(binary)
+
+        binary.analyze_and_wait()
+
+        nat_count = 0
+
+        for ins in binary.processor.instrs:
+            for _, dt in ins.destinations:
+                if dt == ArchInstruction.ILT_EXEC_FLOW:
+                    nat_count += 1
+
+        self.assertEqual(nat_count, 3)
-- 
cgit v0.11.2-87-g4458