Isabelle Hupont

64 papers A 2B 9Journal 30Unranked 22
YearRankTypeTitle / Venue / Authors
2025 J jnl
CoRR
Isabelle Hupont, Marisa Ponti, Sven Schade
2024 B conf
FG
Pablo Negri, Isabelle Hupont, Emilia Gómez
2024 J jnl
CoRR
Pablo Negri, Isabelle Hupont, Emilia Gómez
2024 conf
APF
Delaram Golpayegani, Isabelle Hupont, Cecilia Panigutti, Harshvardhan J. Pandit, Sven Schade, Declan O'Sullivan, Dave Lewis
2024 J jnl
CoRR
Delaram Golpayegani, Isabelle Hupont, Cecilia Panigutti, Harshvardhan J. Pandit, Sven Schade, Declan O'Sullivan, Dave Lewis
2024 J jnl
IEEE Trans. Affect. Comput.
Isabelle Hupont, Songül Tolan, Pedro Frau, Lorenzo Porcaro, Emilia Gómez
2024 conf
CHI Extended Abstracts
Isabelle Hupont, Marina Wainer, Sam Nester, Sylvie Tissot, Lucía Iglesias-Blanco, Sandra Baldassarri
2024 A conf
ECAI
Alexia Gaudeul, Ottla Arrigoni, Vicky Charisi, Marina Escobar-Planas, Isabelle Hupont
2024 J jnl
Ethics Inf. Technol.
Isabelle Hupont, David Fernández Llorca, Sandra Baldassarri, Emilia Gómez
2023 J jnl
CoRR
Lorenzo Porcaro, João Vinagre, Pedro Frau, Isabelle Hupont, Emilia Gómez
2023 J jnl
Computer
Isabelle Hupont, Marina Micheli, Blagoj Delipetrev, Emilia Gómez, Josep Soler Garrido
2023 J jnl
Pattern Recognit.
Parichehr Behjati, Pau Rodríguez, Carles Fernández, Isabelle Hupont, Armin Mehri, Jordi Gonzàlez
2023 J jnl
CoRR
Isabelle Hupont, Marina Wainer, Sam Nester, Sylvie Tissot, Lucía Iglesias-Blanco, Sandra Baldassarri
2023 J jnl
Ethics Inf. Technol.
Marina Micheli, Isabelle Hupont, Blagoj Delipetrev, Josep Soler Garrido
2023 conf
FAccT
Cecilia Panigutti, Ronan Hamon, Isabelle Hupont, David Fernández Llorca, Delia Fano Yela, Henrik Junklewitz, Salvatore Scalzo, Gabriele Mazzini, Ignacio Sánchez, Josep Soler Garrido, Emilia Gómez
2023 J jnl
CoRR
Isabelle Hupont, David Fernández Llorca, Sandra Baldassarri, Emilia Gómez
2022 B conf
ACII
Isabelle Hupont, Emilia Gómez
2022 J jnl
CoRR
Isabelle Hupont, Emilia Gómez
2022 J jnl
CoRR
Isabelle Hupont, Emilia Gómez, Songül Tolan, Lorenzo Porcaro, Ana Freire
2021 J jnl
Frontiers Robotics AI
Giulia Perugia, Maike Paetzel-Prüsmann, Isabelle Hupont, Giovanna Varni, Mohamed Chetouani, Christopher Edward Peters, Ginevra Castellano
2021 J jnl
CoRR
Giulia Perugia, Maike Paetzel-Prüsmann, Isabelle Hupont, Giovanna Varni, Mohamed Chetouani, Christopher Edward Peters, Ginevra Castellano
2021 B conf
ACII
Isabelle Hupont, Songül Tolan, Ana Freire, Lorenzo Porcaro, Sara Estevez, Emilia Gómez
2021 J jnl
CoRR
Isabelle Hupont, Songül Tolan, Ana Freire, Lorenzo Porcaro, Sara Estevez, Emilia Gómez
2021 J jnl
Inf. Fusion
Isabelle Hupont, Eva Cerezo, Sergio Ballano, Sandra Baldassarri
2021 A conf
WACV
Parichehr Behjati, Pau Rodríguez, Armin Mehri, Isabelle Hupont, Carles Fernández Tena, Jordi Gonzàlez
2021 J jnl
IEEE Trans. Biom. Behav. Identity Sci.
Germán Barquero, Isabelle Hupont, Carles Fernández Tena
2021 J jnl
CoRR
Germán Barquero, Isabelle Hupont, Carles Fernández Tena
2020 J jnl
IEEE Trans. Affect. Comput.
Giovanna Varni, Isabelle Hupont, Chloé Clavel, Mohamed Chetouani
2020 J jnl
CoRR
Parichehr Behjati, Pau Rodríguez, Armin Mehri, Isabelle Hupont, Carles Fernández Tena, Jordi Gonzàlez
2020 B conf
IJCB
Germán Barquero, Carles Fernández Tena, Isabelle Hupont
2020 J jnl
CoRR
Germán Barquero, Carles Fernández Tena, Isabelle Hupont
2020 J jnl
CoRR
Parichehr Behjati, Pau Rodríguez, Armin Mehri, Isabelle Hupont, Jordi Gonzàlez, Carles Fernández Tena
2020 J jnl
Inf. Fusion
Francisco Luque Sánchez, Isabelle Hupont, Siham Tabik, Francisco Herrera
2020 ch.
ECHORD++
Giuseppe Palestra, Consuelo Granata, Isabelle Hupont, Mohamed Chetouani
2019 J jnl
Qual. User Exp.
Pierre R. Lebreton, Isabelle Hupont, Matthias Hirth, Toni Mäki, Evangelos Skodras, Anton Schubert, Alexander Raake
2019 B conf
FG
Isabelle Hupont, Carles Fernández Tena
2019 J jnl
Pattern Anal. Appl.
Isabelle Hupont, Mohamed Chetouani
2015 J jnl
Multim. Tools Appl.
Sandra Baldassarri, Isabelle Hupont, David Abadía-Gallego, Eva Cerezo
2015 conf
Human Vision and Electronic Imaging
Pierre R. Lebreton, Toni Mäki, Evangelos Skodras, Isabelle Hupont, Matthias Hirth
2015 conf
CrowdMM@ACM Multimedia
Pierre R. Lebreton, Isabelle Hupont, Toni Mäki, Evangelos Skodras, Matthias Hirth
2015 B conf
QoMEX
Isabelle Hupont, Joaquin Gracia, Luis Miguel Sanagustín, Miguel Angel Gracia
2014 conf
Human Vision and Electronic Imaging
Katrien De Moor, Filippo Mazza, Isabelle Hupont, Miguel Ríos Quintero, Toni Mäki, Martín Varela
2014 conf
HCI (2)
Isabelle Hupont, Eva Cerezo, Sandra Baldassarri, Rafael Del Hoyo
2013 B conf
SMC
Isabelle Hupont, Sandra Baldassarri, Eva Cerezo, Rafael Del Hoyo
2013 J jnl
Pattern Anal. Appl.
Isabelle Hupont, Sandra Baldassarri, Eva Cerezo
2013 B conf
ACII
Isabelle Hupont, Sandra Baldassarri, Eva Cerezo, Rafael Del Hoyo
2012 J jnl
J. Ambient Intell. Humaniz. Comput.
Eva Cerezo, Isabelle Hupont, Sandra Baldassarri, Sergio Ballano
2012 conf
ISNN (2)
Isabelle Hupont, Erik Cambria, Eva Cerezo, Amir Hussain, Sandra Baldassarri
2012 conf
ICAART (1)
Rafael Del Hoyo, Luis Miguel Sanagustín, Carolina Benito, Isabelle Hupont, David Abadía-Gallego
2012 conf
PAAMS (Workshops)
Rafael Del Hoyo, Luis Miguel Sanagustín, Carolina Benito, Isabelle Hupont, David Abadía-Gallego
2011 conf
CSEDU (1)
Héctor Martínez, David Abadía-Gallego, Luis Miguel Sanagustín, Isabelle Hupont, Rafael Del Hoyo, Carlos Sagüés
2011 conf
ICAART (1)
Héctor Martínez, Rafael Del Hoyo, Luis Miguel Sanagustín, Isabelle Hupont, David Abadía-Gallego, Carlos Sagüés
2011 conf
INTERACT (4)
Sergio Ballano, Isabelle Hupont, Eva Cerezo, Sandra Baldassarri
2011 conf
WACI
Isabelle Hupont, Sergio Ballano, Sandra Baldassarri, Eva Cerezo
2011 J jnl
Int. J. Artif. Intell. Tools
Isabelle Hupont, David Abadía-Gallego, Sandra Baldassarri, Eva Cerezo, Rafael Del Hoyo
2010 conf
ICTAI (2)
Isabelle Hupont, David Abadía-Gallego, Sandra Baldassarri, Eva Cerezo, Rafael Del Hoyo
2010 B conf
SMC
Isabelle Hupont, Eva Cerezo, Sandra Baldassarri
2010 conf
COST 2102 Training School
Erik Cambria, Isabelle Hupont, Amir Hussain, Eva Cerezo, Sandra Baldassarri
2009 conf
AFFINE@ICMI
Rafael del-Hoyo, Isabelle Hupont, Francisco José Lacueva-Pérez, David Abadía-Gallego
2009 conf
AFFINE@ICMI
Isabelle Hupont, Rafael Del Hoyo, Sandra Baldassarri, Eva Cerezo, Francisco J. Serón, Diego Romero
2008 conf
AMDO
Isabelle Hupont, Sandra Baldassarri, Rafael Del Hoyo, Eva Cerezo
2007 conf
IbPRIA (2)
Eva Cerezo, Isabelle Hupont, Cristina Manresa-Yee, Xavier Varona, Sandra Baldassarri, Francisco José Perales López, Francisco J. Serón
2006 conf
AMDO
Eva Cerezo, Isabelle Hupont
2006 conf
SIACG
Isabelle Hupont, Eva Cerezo
tests/unit/test_decompile_decompiler.py
← Index tests/unit/test_decompile_decompiler.py python
"""Unit tests (mocked BN) for bninja/decompiler.py — BinaryNinjaDecompiler."""
import sys
import json
import time
import pytest
from unittest.mock import MagicMock, patch, mock_open

from tests.unit.conftest_binja_stubs import (
    install_binja_stubs,
    MockFunction,
    MockBasicBlock,
    MockDisassemblyLine,
    MockToken,
    MockSymbol,
    MockBinaryView,
    MockEdge,
    SymbolType,
    InstructionTextTokenType,
    BranchType,
)

install_binja_stubs()

from redb.extractors.decompiler.bninja.decompiler import (
    BinaryNinjaDecompiler,
    is_lib_or_thunk,
)
from redb.extractors.decompiler.bninja.function_type import FunctionType


# ============================================================================
# 10a. BinaryNinjaDecompiler
# ============================================================================


class TestBinaryNinjaDecompilerLogError:
    def _make_decompiler(self):
        with patch.object(BinaryNinjaDecompiler, "__init__", lambda self, *a, **kw: None):
            d = BinaryNinjaDecompiler.__new__(BinaryNinjaDecompiler)
            d.log = MagicMock()
            d.errors = []
            d.filepath = "/fake/binary"
            d.bv = None
            d.analysis_results = None
            d.exporters = []
            d.index_prefix = None
            d.filetype = None
            d.goresym = None
            d.BNINJA_TIMEOUT = 60
            return d

    def test_log_error_appends(self):
        d = self._make_decompiler()
        d.log_error("test error", "func1", 0x1000, Exception("boom"), "extract")
        assert len(d.errors) == 1

    def test_log_error_schema(self):
        d = self._make_decompiler()
        d.log_error("test error", "func1", 0x1000, Exception("boom"), "extract")
        error = d.errors[0]
        expected_keys = [
            "function_name",
            "function_address",
            "error_location",
            "error_message",
            "error_details",
            "error_type",
            "timestamp",
        ]
        for key in expected_keys:
            assert key in error, f"Missing key: {key}"


class TestBinaryNinjaDecompilerIsTooFewBlocks:
    def _make_decompiler(self):
        with patch.object(BinaryNinjaDecompiler, "__init__", lambda self, *a, **kw: None):
            d = BinaryNinjaDecompiler.__new__(BinaryNinjaDecompiler)
            d.log = MagicMock()
            d.errors = []
            d.MIN_FUNCTION_SIZE = 10
            return d

    def test_is_too_few_blocks_none(self):
        d = self._make_decompiler()
        func = MagicMock()
        func.basic_blocks = None
        assert d.is_too_few_blocks(func) is False

    def test_is_too_few_blocks_empty(self):
        # Empty basic_blocks now returns True because Binja creates function
        # stubs with empty blocks before analysis completes — we no longer
        # skip these so they get filtered downstream instead.
        d = self._make_decompiler()
        func = MagicMock()
        func.basic_blocks = []
        assert d.is_too_few_blocks(func) is True

    def test_is_too_few_blocks_small_single(self):
        d = self._make_decompiler()
        block = MagicMock()
        block.disassembly_text = [MagicMock() for _ in range(5)]  # < 10
        func = MagicMock()
        func.basic_blocks = [block]
        assert d.is_too_few_blocks(func) is False

    def test_is_too_few_blocks_large_single(self):
        d = self._make_decompiler()
        block = MagicMock()
        block.disassembly_text = [MagicMock() for _ in range(15)]  # >= 10
        func = MagicMock()
        func.basic_blocks = [block]
        assert d.is_too_few_blocks(func) is True

    def test_is_too_few_blocks_multiple(self):
        d = self._make_decompiler()
        func = MagicMock()
        func.basic_blocks = [MagicMock(), MagicMock()]
        assert d.is_too_few_blocks(func) is True


class TestIsLibOrThunk:
    def test_is_lib_or_thunk_user(self):
        func = MagicMock()
        func.symbol.type = SymbolType.FunctionSymbol
        func.is_thunk = False
        assert is_lib_or_thunk(func) is True  # NOT filtered

    def test_is_lib_or_thunk_thunk(self):
        func = MagicMock()
        func.symbol.type = SymbolType.FunctionSymbol
        func.is_thunk = True
        assert is_lib_or_thunk(func) is False  # Filtered out

    def test_is_lib_or_thunk_external(self):
        func = MagicMock()
        func.symbol.type = SymbolType.ImportedFunctionSymbol
        func.is_thunk = False
        assert is_lib_or_thunk(func) is False  # Filtered out


class TestBinaryNinjaDecompilerExtract:
    def _make_decompiler(self):
        with patch.object(BinaryNinjaDecompiler, "__init__", lambda self, *a, **kw: None):
            d = BinaryNinjaDecompiler.__new__(BinaryNinjaDecompiler)
            d.log = MagicMock()
            d.errors = []
            d.filepath = "/fake/binary"
            d.bv = MagicMock()
            d.analysis_results = None
            d.exporters = []
            d.index_prefix = None
            d.filetype = None
            d.goresym = None
            d.BNINJA_TIMEOUT = 60
            d.arch = MagicMock()
            return d

    def test_extract_success(self):
        d = self._make_decompiler()
        mock_results = {
            "decompiled": [{"test": True}],
            "disassembled": [],
            "cfg": [],
            "llil": [],
            "errors": [],
            "strings": [],
            "mlil": [],
        }
        with patch.object(d, "analyze_binary", return_value=mock_results):
            result = d.extract()
            assert result is True
            assert d.analysis_results == mock_results

    def test_extract_failure(self):
        d = self._make_decompiler()
        with patch.object(d, "analyze_binary", return_value=None):
            result = d.extract()
            assert result is False

    def test_tag(self):
        d = self._make_decompiler()
        assert d.tag() == "DECOMPILED"


class TestBinaryNinjaDecompilerAnalyzeBinary:
    def _make_decompiler(self):
        with patch.object(BinaryNinjaDecompiler, "__init__", lambda self, *a, **kw: None):
            d = BinaryNinjaDecompiler.__new__(BinaryNinjaDecompiler)
            d.log = MagicMock()
            d.errors = []
            d.filepath = "/fake/binary"
            d.analysis_results = None
            d.exporters = []
            d.index_prefix = None
            d.filetype = None
            d.goresym = None
            d.BNINJA_TIMEOUT = 60
            d.arch = MagicMock()
            d.MIN_FUNCTION_SIZE = 10
            return d

    def test_analyze_binary_links_hlil_disasm(self):
        """Bi-directional hash linkage between decompiled and disassembled."""
        d = self._make_decompiler()
        d.bv = MagicMock()
        d.bv.functions = []
        # Mock methods to return controlled data
        with patch.object(d, "extract_hlil") as mock_hlil, \
             patch.object(d, "extract_disasm") as mock_disasm, \
             patch.object(d, "extract_cfg", return_value=None), \
             patch.object(d, "extract_lowlevel", return_value=None):

            mock_hlil.return_value = {
                "decompiled_function_hash": "HLIL_HASH",
                "decompiled_function_name": "test",
                "decompiled_function": "code",
            }
            mock_disasm.return_value = {
                "disassembled_function_hash": "DISASM_HASH",
                "disassembled_function_no_addresses": "asm",
            }

            # Manually feed one function
            mock_func = MagicMock()
            mock_func.symbol.type = SymbolType.FunctionSymbol
            mock_func.is_thunk = False
            mock_func.basic_blocks = [MagicMock(), MagicMock()]
            d.bv.functions = [mock_func]

            results = d.analyze_binary()
            if results and results["decompiled"]:
                hlil_r = results["decompiled"][0]
                disasm_r = results["disassembled"][0]
                assert hlil_r["disassembled_function_hash"] == "DISASM_HASH"
                assert disasm_r["decompiled_function_hash"] == "HLIL_HASH"

    def test_analyze_binary_links_llil_disasm(self):
        """Bi-directional linkage between LLIL and disassembly."""
        d = self._make_decompiler()
        d.bv = MagicMock()

        with patch.object(d, "extract_hlil", return_value=None), \
             patch.object(d, "extract_disasm") as mock_disasm, \
             patch.object(d, "extract_cfg", return_value=None), \
             patch.object(d, "extract_lowlevel") as mock_llil:

            mock_disasm.return_value = {
                "disassembled_function_hash": "DISASM_HASH",
                "disassembled_function_no_addresses": "asm",
            }
            mock_llil.return_value = {
                "sha256_llil": "LLIL_HASH",
                "tlsh_llil": "tlsh_val",
            }

            mock_func = MagicMock()
            mock_func.symbol.type = SymbolType.FunctionSymbol
            mock_func.is_thunk = False
            mock_func.basic_blocks = [MagicMock(), MagicMock()]
            d.bv.functions = [mock_func]

            results = d.analyze_binary()
            if results and results["llil"]:
                llil_r = results["llil"][0]
                assert llil_r["disassembled_function_hash"] == "DISASM_HASH"

    def test_analyze_binary_links_cfg_disasm(self):
        """CFG gets disassembled_function_hash."""
        d = self._make_decompiler()
        d.bv = MagicMock()

        with patch.object(d, "extract_hlil", return_value=None), \
             patch.object(d, "extract_disasm") as mock_disasm, \
             patch.object(d, "extract_cfg") as mock_cfg, \
             patch.object(d, "extract_lowlevel", return_value=None):

            mock_disasm.return_value = {
                "disassembled_function_hash": "DISASM_HASH",
                "disassembled_function_no_addresses": "asm",
            }
            mock_cfg.return_value = {
                "function_address": 0x1000,
                "cyclomatic_complexity": 3,
            }

            mock_func = MagicMock()
            mock_func.symbol.type = SymbolType.FunctionSymbol
            mock_func.is_thunk = False
            mock_func.basic_blocks = [MagicMock(), MagicMock()]
            d.bv.functions = [mock_func]

            results = d.analyze_binary()
            if results and results["cfg"]:
                cfg_r = results["cfg"][0]
                assert cfg_r["disassembled_function_hash"] == "DISASM_HASH"

    def test_analyze_binary_sets_cyclomatic(self):
        """cyclomatic_complexity set on disasm from CFG."""
        d = self._make_decompiler()
        d.bv = MagicMock()

        with patch.object(d, "extract_hlil", return_value=None), \
             patch.object(d, "extract_disasm") as mock_disasm, \
             patch.object(d, "extract_cfg") as mock_cfg, \
             patch.object(d, "extract_lowlevel", return_value=None):

            mock_disasm.return_value = {
                "disassembled_function_hash": "HASH",
                "disassembled_function_no_addresses": "asm",
            }
            mock_cfg.return_value = {
                "function_address": 0x1000,
                "cyclomatic_complexity": 7,
            }

            mock_func = MagicMock()
            mock_func.symbol.type = SymbolType.FunctionSymbol
            mock_func.is_thunk = False
            mock_func.basic_blocks = [MagicMock(), MagicMock()]
            d.bv.functions = [mock_func]

            results = d.analyze_binary()
            if results and results["disassembled"]:
                disasm_r = results["disassembled"][0]
                assert disasm_r.get("cyclomatic_complexity") == 7


class TestApplyGoReSym:
    def _make_decompiler(self):
        with patch.object(BinaryNinjaDecompiler, "__init__", lambda self, *a, **kw: None):
            d = BinaryNinjaDecompiler.__new__(BinaryNinjaDecompiler)
            d.log = MagicMock()
            d.errors = []
            d.bv = MagicMock()
            return d

    def test_apply_goresym_user_functions(self):
        d = self._make_decompiler()
        d.goresym = "/tmp/goresym.json"
        data = {
            "UserFunctions": [{"Start": 0x1000, "FullName": "main.main"}],
        }
        with patch("builtins.open", mock_open(read_data=json.dumps(data))):
            d._BinaryNinjaDecompiler__apply_goresym()
            d.bv.define_user_symbol.assert_called()

    def test_apply_goresym_std_functions(self):
        d = self._make_decompiler()
        d.goresym = "/tmp/goresym.json"
        data = {
            "StdFunctions": [{"Start": 0x2000, "FullName": "runtime.main"}],
        }
        with patch("builtins.open", mock_open(read_data=json.dumps(data))):
            d._BinaryNinjaDecompiler__apply_goresym()
            d.bv.define_user_symbol.assert_called()

    def test_apply_goresym_invalid_json(self):
        d = self._make_decompiler()
        d.goresym = "/tmp/goresym.json"
        with patch("builtins.open", mock_open(read_data="not json {")):
            d._BinaryNinjaDecompiler__apply_goresym()
            # Should log error but not crash
            d.log.log_error if hasattr(d.log, 'log_error') else None
            # Just verify no exception raised