Carlo Ferrari

63 papers A* 1A 2B 1C 7Misc 1Journal 20Unranked 30
YearRankTypeTitle / Venue / Authors
2025 conf
edu4AI@ECAI
Silvana Badaloni, Carlo Ferrari, Antonio Rodà
2024 J jnl
Bioinform.
Soroush Mozaffari, Paula Nazarena Arrías, Damiano Clementel, Damiano Piovesan, Carlo Ferrari, Silvio C. E. Tosatto, Alexander Miguel Monzon
2023 conf
UCAmI (3)
Carlo Ferrari
2022 conf
UCAmI
Mauro Migliardi, Meriem Guerar, S. Marzio, Carlo Ferrari
2022 J jnl
BMC Bioinform.
Michela Quadrini, Sebastian Daberdaku, Carlo Ferrari
2021 conf
LOD
Michela Quadrini, Massimo Cavallin, Sebastian Daberdaku, Carlo Ferrari
2020 C conf
ETFA
Daniele Evangelista, Matteo Terreran, Alberto Pretto, Michele Moro, Carlo Ferrari, Emanuele Menegatti
2020 conf
LOD (2)
Michela Quadrini, Sebastian Daberdaku, Carlo Ferrari
2020 conf
MetroInd4.0&IoT
Daniele Evangelista, Marco Antonelli, Alberto Pretto, Christian Eitzinger, Michele Moro, Carlo Ferrari, Emanuele Menegatti
2019 J jnl
Bioinform.
Sebastian Daberdaku, Carlo Ferrari
2018 conf
AINA Workshops
Carlo Ferrari, Daniele Marini, Michele Moro
2018 J jnl
Int. J. High Perform. Comput. Appl.
Sebastian Daberdaku, Carlo Ferrari
2018 J jnl
BMC Bioinform.
Sebastian Daberdaku, Carlo Ferrari
2018 conf
HPCS
Sebastian Daberdaku, Carlo Ferrari
2018 conf
UCAmI
Davide Pedrini, Mauro Migliardi, Carlo Ferrari, Alessio Merlo
2017 Misc conf
CISIS
Carlo Ferrari, Michele Moro
2017 J jnl
Algorithms
Elisabetta Stefani, Carlo Ferrari
2015 J jnl
Bioinform.
Ian Walsh, Manuel Giollo, Tomás Di Domenico, Carlo Ferrari, Olav Zimmermann, Silvio C. E. Tosatto
2015 conf
CIBB
Sebastian Daberdaku, Carlo Ferrari
2015 J jnl
Nucleic Acids Res.
Damiano Piovesan, Manuel Giollo, Emanuela Leonardi, Carlo Ferrari, Silvio C. E. Tosatto
2015 conf
ECOC
Haoshuo Chen, Nicolas K. Fontaine, Binbin Guan, Burcu Ercan, Yumeng Zhang, Roland Ryf, Mark Cappuzzo, Bob Keller, Yongkang Gao, Carlo Ferrari, Ryan P. Scott, S. J. Ben Yoo
2015 conf
TrustCom/BigDataSE/ISPA (3)
Sebastian Daberdaku, Carlo Ferrari
2015 J jnl
Bioinform.
Layla Hirsh, Damiano Piovesan, Manuel Giollo, Carlo Ferrari, Silvio C. E. Tosatto
2014 conf
ECOC
Carlo Ferrari, Cristian A. Bolle, Mark Cappuzzo, R. Keller, Fred Klemens, Yee L. Low, Nagesh Basavanhally, A. R. Papazian, Flavio Pardo, Mark P. Earnshaw
2014 conf
OFC
Chuan Qin, Binbin Guan, Ryan P. Scott, Roberto Proietti, Nicolas K. Fontaine, Tiehui Su, Carlo Ferrari, Mark Cappuzzo, Fred Klemens, Bob Keller, Mark P. Earnshaw, S. J. Ben Yoo
2014 J jnl
Nucleic Acids Res.
Tomás Di Domenico, Emilio Potenza, Ian Walsh, R. Gonzalo Parra, Manuel Giollo, Giovanni Minervini, Damiano Piovesan, Awais Ihsan, Carlo Ferrari, Andrey V. Kajava, Silvio C. E. Tosatto
2013 J jnl
Bell Labs Tech. J.
Wolfgang Pöhlmann, Bernhard Deppisch, Thomas Pfeiffer, Carlo Ferrari, Mark P. Earnshaw, Alex Duque, Robert L. Farah, Joe Galaro, James Kotch, Man Fai Lau, Doutje T. van Veen, Peter Vetter
2012 conf
AIMM
Manuel Giollo, Giovanni Minervini, Marta Scalzotto, Emanuela Leonardi, Carlo Ferrari, Silvio C. E. Tosatto
2012 J jnl
Bioinform.
Ian Walsh, Francesco Sirocco, Giovanni Minervini, Tomás Di Domenico, Carlo Ferrari, Silvio C. E. Tosatto
2012 conf
IWAAL
Alexandru Egner, Alexandru Soceanu, Florica Moldoveanu, Carlo Ferrari, Michele Moro
2010 conf
WOA
Marco Tranquillin, Carlo Ferrari, Michele Moro
2010
Carlo Ferrari
2008 conf
Web Intelligence/IAT Workshops
Cristian Bertocco, Carlo Ferrari
2005 B conf
CPM
Mary Ellen Bock, Guido Maria Cortelazzo, Carlo Ferrari, Concettina Guerra
2004 J jnl
Parallel Process. Lett.
Matteo Comin, Carlo Ferrari, Concettina Guerra
2004 conf
SAG
Mario Cannataro, Matteo Comin, Carlo Ferrari, Concettina Guerra, Antonella Guzzo, Pierangelo Veltri
2003 J jnl
J. Parallel Distributed Comput.
Carlo Ferrari, Concettina Guerra, Giuseppe Zanotti
2003 J jnl
Adv. Robotics
Enrico Pagello, Antonio D'Angelo, Carlo Ferrari, Roberto Polesel, Robert Rosati, Alberto Speranzon
2003 conf
Mathematical Methods for Protein Structure Analysis and Design
Carlo Ferrari, Concettina Guerra
2002 conf
OTM
Francesco Garelli, Carlo Ferrari
2002 J jnl
Robotics Auton. Syst.
Stefano Carpin, Carlo Ferrari, Enrico Pagello
2001 conf
WOA
Francesco Garelli, Carlo Ferrari
2000 conf
DARS
Stefano Carpin, Carlo Ferrari, Enrico Pagello
2000 conf
Balancing Reactivity and Social Deliberation in Multi-Agent Systems
Stefano Carpin, Carlo Ferrari, Enrico Pagello, Pierluigi Patuelli
2000 C conf
RoboCup
Massimo Ferraresso, Carlo Ferrari, Enrico Pagello, Roberto Polesel, Robert Rosati, Alberto Speranzon, Walter Zanette
2000 conf
WOA
Francesco Garelli, Carlo Ferrari
2000 C conf
RoboCup
Carlo Ferrari, Francesco Garelli, Enrico Pagello
2000 A conf
IROS
Roberto Polesel, Robert Rosati, Alberto Speranzon, Carlo Ferrari, Enrico Pagello
1999 J jnl
Robotics Auton. Syst.
Enrico Pagello, Antonio D'Angelo, Federico Montesello, Francesco Garelli, Carlo Ferrari
1999 C conf
RoboCup
Carlo Ferrari, Francesco Garelli, Enrico Pagello
1998 conf
DARS
Federico Montesello, Antonio D'Angelo, Carlo Ferrari, Enrico Pagello
1998 conf
Mobile Robots / Intelligent Transportation Systems
Giuseppe Borghi, Carlo Ferrari, Enrico Pagello, Marco Vianello
1998 J jnl
Robotics Auton. Syst.
Carlo Ferrari, Enrico Pagello, Jun Ota, Tamio Arai
1997 C conf
RoboCup
Enrico Pagello, Federico Montesello, Antonio D'Angelo, Carlo Ferrari
1997 conf
CIRA
Carlo Ferrari, Enrico Pagello, Matteo Voltolina, Jun Ota, Tamio Arai
1996 A conf
IROS
Carlo Ferrari, Enrico Pagello, Jun Ota, Tamio Arai
1995 conf
AI*IA
Carlo Ferrari, Enrico Pagello, Jun Ota, Tamio Arai
1995 J jnl
J. Intell. Robotic Syst.
Paolo Bison, Carlo Ferrari, Enrico Pagello, L. Stocchiero
1995 conf
IROS (2)
Carlo Ferrari, Enrico Pagello, Jun Ota, Tamio Arai
1992 A* conf
ICRA
Carlo Ferrari, John F. Canny
1992 J jnl
Int. J. Man Mach. Stud.
Fausto Giunchiglia, Carlo Ferrari, Paolo Traverso, Emanuele Trucco
1989 C conf
IAS
Carlo Ferrari, Gaetano Chemello
1986 C conf
IAS
Mauro Di Manzo, Franca Ricci, F. Adriana Batistoni, Carlo Ferrari
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