Nan Deng

55 papers A* 2A 2B 2Misc 1Journal 32Unranked 15
YearRankTypeTitle / Venue / Authors
2026 J jnl
IEEE Access
Yuetong Liu, Qifan Yang, Bowen Han, Bingru Li, Nan Deng, Xuehui Chang
2026 J jnl
CoRR
Nan Deng, Wanrong Cao
2025 J jnl
CoRR
Nan Deng, Yibo Wang, Wanrong Cao
2025 J jnl
J. Frankl. Inst.
Cheng Han, Zhengguang Xu, Nan Deng
2025 J jnl
Comput. Phys. Commun.
Antonio Colanera, Nan Deng, Matteo Chiatto, Luigi de Luca, Bernd R. Noack
2025 J jnl
CoRR
Sixiang Zhou, Nan Deng, Krzysiek Rzadca, Charlie Y. Hu, Xiaojun Lin
2025 B conf
IEEE Big Data
Ali Zafar Sadiq, Haiying Shen, Tanmoy Sen, Nan Deng, Sunan Xiang
2025 J jnl
Nat. Comput. Sci.
Nan Deng, Xifeng Gu, Ying Fan, Shlomo Havlin, An Zeng
2024 J jnl
Remote. Sens.
Nan Deng, YanJie Li, He Ma, Feifei Zhang
2024 J jnl
J. Comput. Appl. Math.
Nan Deng, Wanrong Cao
2024 J jnl
IEEE J. Sel. Top. Appl. Earth Obs. Remote. Sens.
Kehui Liu, Nan Deng, Yanxia Wang, Xuejun Tian, Jian Cheng
2023 J jnl
Scientometrics
Nan Deng, An Zeng
2023 J jnl
IEEE Trans. Cloud Comput.
Akshay Jajoo, Y. Charlie Hu, Xiaojun Lin, Nan Deng
2022 Misc conf
NSDI
Akshay Jajoo, Y. Charlie Hu, Xiaojun Lin, Nan Deng
2022 J jnl
Remote. Sens.
Nan Deng, Weihua Bai, Yueqiang Sun, Qifei Du, Junming Xia, Xianyi Wang, Congliang Liu, Yuerong Cai, Xiangguang Meng, Cong Yin, Feixiong Huang, Peng Hu, Guangyuan Tan, Xiaoxu Liu
2022 J jnl
Int. J. Pattern Recognit. Artif. Intell.
Cheng Li, Ming Li, Xinghui Zhu, Yineng Chen, Yanbin Wu, Nan Deng, Kui Fang
2022 J jnl
Database J. Biol. Databases Curation
Nan Deng, Canglin Wu, Ashraf Yaseen, Hulin Wu
2022 J jnl
Int. J. Inf. Commun. Technol.
Nan Deng, Shichao Geng, Shaorui Hao, Qin Zhang, Lanjuan Li
2022 J jnl
Appl. Math. Lett.
Meiqiang Feng, Nan Deng
2022 J jnl
J. Comput. Appl. Math.
Nan Deng, Wanrong Cao, Guofei Pang
2021 J jnl
Briefings Bioinform.
Yunlong Wang, Yaqi Liu, Qian Xu, Yao Xu, Kai Cao, Nan Deng, Ruimin Wang, Xueying Zhang, Ruiqin Zheng, Guoliang Li, Yaping Fang
2021 A conf
EuroSys
Noman Bashir, Nan Deng, Krzysztof Rzadca, David Irwin, Sree Kodak, Rohit Jnagal
2021 J jnl
Symmetry
Nan Deng, Qin Zhang
2021 J jnl
CoRR
Akshay Jajoo, Y. Charlie Hu, Xiaojun Lin, Nan Deng
2020 J jnl
J. Biomed. Informatics
Braja Gopal Patra, Vahed Maroufy, Babak Soltanalizadeh, Nan Deng, W. Jim Zheng, Kirk Roberts, Hulin Wu
2020 J jnl
Database J. Biol. Databases Curation
Braja Gopal Patra, Babak Soltanalizadeh, Nan Deng, Leqing Wu, Vahed Maroufy, Canglin Wu, W. Jim Zheng, Kirk Roberts, Hulin Wu, Ashraf Yaseen
2020 A conf
EuroSys
Muhammad Tirmazi, Adam Barker, Nan Deng, Md E. Haque, Zhijing Gene Qin, Steven Hand, Mor Harchol-Balter, John Wilkes
2020 conf
DI2KG@VLDB
Nan Deng, Wendi Luan, Haotian Liu, Bo Tang
2020 J jnl
ERCIM News
Nan Deng, Luc Pastur, Bernd R. Noack
2020 J jnl
Symmetry
Nan Deng, Qin Zhang
2019 J jnl
BMC Medical Informatics Decis. Mak.
Boyu Tan, Junyuan Gu, Hongyan Wei, Li Chen, Sulan Yan, Nan Deng
2019 J jnl
Database J. Biol. Databases Curation
Guocai Chen, Juan Camilo Ramírez, Nan Deng, Xing Qiu, Canglin Wu, W. Jim Zheng, Hulin Wu
2019 A* conf
ASPLOS
H. Andrés Lagar-Cavilla, Junwhan Ahn, Suleiman Souhlal, Neha Agarwal, Radoslaw Burny, Shakeel Butt, Jichuan Chang, Ashwin Chaugule, Nan Deng, Junaid Shahid, Greg Thelen, Kamil Adam Yurtsever, Yu Zhao, Parthasarathy Ranganathan
2017 ch.
Encyclopedia of GIS
Udit Bhatia, Allison Traylor, Catherine Moskos, Laura Blumenfeld, Lindsey Bressler, Tyler Hall, Rachael Heiss, Kevin D. Clark, Nan Deng, Devashish Kumar, Evan Kodra, Stephen E. Flynn, Haris N. Koutsopoulos, Jerome F. Hajjar, Auroop R. Ganguly
2017 conf
OFC
Xiaoyi Tian, Weilin Xie, Xiaocheng Wang, Jie Qin, Nan Deng, Yi Dong, Weisheng Hu
2016 A* conf
INFOCOM
Zichen Xu, Christopher Stewart, Nan Deng, Xiaorui Wang
2016 conf
IntelliSys (1)
Manolo Dulva Hina, Hongyu Guan, Nan Deng, Amar Ramdane-Cherif
2016 conf
ITSC
Manolo Dulva Hina, Hongyu Guan, Amar Ramdane-Cherif, Nan Deng
2016 J jnl
J. Comput. Biol.
Zhenqiu Liu, Shili Lin, Nan Deng, Dermot P. B. McGovern, Steven T. Piantadosi
2015 conf
ICAC
Zichen Xu, Nan Deng, Christopher Stewart, Xiaorui Wang
2015 conf
IGSC
Nan Deng, Zichen Xu, Christopher Stewart, Xiaorui Wang
2014 J jnl
BMC Bioinform.
Yan Jiao, Xiaoyun Liu, Yanhong Cao, Nan Deng, Yonghui Ma, Karen A. Hasty, John M. Stuart, Weikuan Gu
2014 conf
Feedback Computing
Nan Deng, Zichen Xu, Christopher Stewart, Xiaorui Wang
2014 conf
ISBRA
Nan Deng, Dongxiao Zhu
2013 conf
BCB
Nan Deng, Dongxiao Zhu
2013 J jnl
J. Multim.
Nan Deng, Zhengguang Xu, Jun Wang
2013 conf
BCB
Nan Deng, Dongxiao Zhu
2012 conf
ICAC
Nan Deng, Christopher Stewart, Daniel Gmach, Martin F. Arlitt, Jaimie Kelley
2012 B conf
NOMS
Nan Deng, Christopher Stewart, Daniel Gmach, Martin F. Arlitt
2012 J jnl
CoRR
Tin Chi Nguyen, Nan Deng, Dongxiao Zhu
2011 J jnl
Source Code Biol. Medicine
Guorong Xu, Nan Deng, Zhiyu Zhao, Thair Judeh, Erik K. Flemington, Dongxiao Zhu
2011 conf
BIBM Workshops
Zhiyu Zhao, Tin Chi Nguyen, Nan Deng, Kristen Marie Johnson, Dongxiao Zhu
2011 conf
BIBM Workshops
Tin Chi Nguyen, Nan Deng, Guorong Xu, Zhansheng Duan, Dongxiao Zhu
2010 conf
AICI (1)
Zhenyong Fu, Hongtao Lu, Nan Deng, Nengbin Cai
2010 conf
AICI (1)
Jiongyun Xie, Hongtao Lu, Nan Deng, Nengbin Cai
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