Ce Li

63 papers A* 3B 3C 1Journal 37Unranked 19
YearRankTypeTitle / Venue / Authors
2026 J jnl
Inf. Process. Manag.
Zongshun Wang, Ce Li, Jialin Ma, Zhiqiang Feng, Pengcheng Wang, Xiaodong Wang, Limei Xiao
2026 J jnl
Knowl. Based Syst.
Zongshun Wang, Ce Li, Zhiqiang Feng, Limei Xiao, Pengcheng Wang, Mengmeng Ping
2025 J jnl
Knowl. Based Syst.
Jialin Ma, Ce Li, Zhiqiang Feng, Limei Xiao, Chengdan He, Yan Zhang
2025 J jnl
Eng. Appl. Artif. Intell.
Jialin Ma, Ce Li, Zhiqiang Feng, Limei Xiao
2025 J jnl
Appl. Intell.
Jialin Ma, Ce Li, Liang Hong, Kailun Wei, Shutian Zhao, Hangfei Jiang, Yanyun Qu
2024 J jnl
IEEE Trans. Neural Networks Learn. Syst.
Ce Li, Fenghua Liu, Zhiqiang Tian, Shaoyi Du, Yang Wu
2024 conf
CyberC
Teng Wan, Shaoyi Du, Qiang Zhang, Ying Qi, Ce Li
2024 J jnl
Inf.
Zongshun Wang, Ce Li, Jialin Ma, Zhiqiang Feng, Limei Xiao
2023 J jnl
Concurr. Comput. Pract. Exp.
Limei Xiao, Yachao Zhang, Weizhe Gao, Dayou Xu, Ce Li
2023 J jnl
Pattern Recognit.
Dong Zhang, Jing Yang, Shaoyi Du, Hongcheng Han, Yuyan Ge, Longfei Zhu, Ce Li, Meifeng Xu, Nanning Zheng
2023 J jnl
CoRR
Yaqian Guo, Xin Wang, Ce Li, Shihui Ying
2023 J jnl
Comput. Electr. Eng.
Limei Xiao, Zizhong Zhu, Hao Liu, Ce Li, Wenhao Fu
2023 J jnl
Int. J. Mach. Learn. Cybern.
Ce Li, Shuxing Xuan, Fenghua Liu, Enbing Chang, Hailei Wu
2023 J jnl
Comput. Vis. Image Underst.
Hao Liu, Ce Li, Shangang Jin, Weizhe Gao, Fenghua Liu, Shaoyi Du, Shihui Ying
2022 A* conf
CVPR
Zhang Chen, Zhiqiang Tian, Jihua Zhu, Ce Li, Shaoyi Du
2022 J jnl
IEEE Trans. Neural Networks Learn. Syst.
Teng Wan, Shaoyi Du, Wenting Cui, Runzhao Yao, Yuyan Ge, Ce Li, Yue Gao, Nanning Zheng
2022 J jnl
Frontiers Comput. Sci.
Tian Wang, Jiakun Li, Huai-Ning Wu, Ce Li, Hichem Snoussi, Yang Wu
2021 J jnl
Comput. Electr. Eng.
Limei Xiao, Tian Lan, Dayou Xu, Weizhe Gao, Ce Li
2021 conf
CONF-SPML
Longshuai Sheng, Ce Li, Yihan Tian
2021 J jnl
Neurocomputing
Zhiqiang Tian, Xiaojian Li, Zhang Chen, Yaoyue Zheng, Hongcheng Fan, Zhongyu Li, Ce Li, Shaoyi Du
2021 J jnl
Multim. Tools Appl.
Runzhao Yao, Shaoyi Du, Teng Wan, Wenting Cui, Yang Yang, Yang Jing, Ce Li
2021 conf
PRCV (3)
Ce Li, Enbing Chang, Fenghua Liu, Shuxing Xuan, Jie Zhang, Tian Wang
2020 J jnl
Neurocomputing
Zhongyu Li, Jiamin Liu, Zhiqiang Tian, Jihua Zhu, Ce Li, Shaoyi Du
2020 J jnl
IEEE Access
Ce Li, Dong Zhang, Shaoyi Du, Zhiqiang Tian
2020 J jnl
Neurocomputing
Yang Zhang, Zhengfeng Zhang, Qingyu Yang, Dou An, Donghe Li, Ce Li
2020 J jnl
IET Image Process.
Hao Liu, Ce Li, Dong Zhang, Yannan Zhou, Shaoyi Du
2020 J jnl
IEEE Access
Teng Wan, Shaoyi Du, Wenting Cui, Yang Yang, Ce Li
2020 J jnl
Neural Comput. Appl.
Rong Chen, Yanyun Qu, Cuihua Li, Kun Zeng, Yuan Xie, Ce Li
2019 J jnl
IEEE Trans. Inf. Forensics Secur.
Tian Wang, Meina Qiao, Zhiwei Lin, Ce Li, Hichem Snoussi, Zhe Liu, Chang Choi
2019 J jnl
Pattern Recognit. Lett.
Ce Li, Xinyu Zhao, Zhaoxiang Zhang, Shaoyi Du
2018 J jnl
Neural Process. Lett.
Ce Li, Bing Lu, Yachao Zhang, Hao Liu, Yanyun Qu
2018 J jnl
Multim. Tools Appl.
Tian Wang, Meina Qiao, Aichun Zhu, Yida Niu, Ce Li, Hichem Snoussi
2018 conf
ICACI
Ce Li, Yachao Zhang, Yanyun Qu
2018 conf
ICIMCS
Ce Li, Yuqi Wan, Shengze Jia, Hao Liu
2017 conf
CCCV (1)
Hao Liu, Ce Li, Yuqi Wan, Yachao Zhang
2017 J jnl
Neurocomputing
Ce Li, Qiang Ma, Limei Xiao, Ming Li, Aihua Zhang
2017 conf
ACPR
Ce Li, Xinyu Zhao, Hao Liu, Limei Xiao
2017 conf
ICONIP (3)
Ce Li, Yuqi Wan, Hao Liu
2017 conf
ICONIP (3)
Ce Li, Xinyu Zhao, Yuqi Wan
2016 conf
CISP-BMEI
Teng Wan, Ce Li, Yachao Zhang
2016 J jnl
Neurocomputing
Ce Li, Yang Yang, Limei Xiao, Yongxin Li, Yannan Zhou, Jizhong Zhao
2016 conf
ICIMCS
Ce Li, Qiang Ma, Limei Xiao, Shihui Ying
2016 J jnl
Neurocomputing
Limei Xiao, Ce Li, Zongze Wu, Tian Wang
2016 conf
ICIC (2)
Yuqi Zhang, Tian Wang, Meina Qiao, Aichun Zhu, Ce Li, Hichem Snoussi
2016 conf
ICIC (2)
Limei Xiao, Ce Li, Zhijia Hu, Zhengrong Pan
2016 conf
CISP-BMEI
Ce Li, Haozuo Wei, Tian Lan
2016 conf
ICIC (2)
Ce Li, Ming Li, Limei Xiao, Beijie Ren
2015 J jnl
Multim. Tools Appl.
Lihua Tian, Nanning Zheng, Jianru Xue, Ce Li
2015 conf
ICIC (2)
Ce Li, Qiang Ma, Limei Xiao, Ming Li, Aihua Zhang
2015 conf
ICIC (3)
Ce Li, Qiang Ma, Limei Xiao, Ming Li, Aihua Zhang
2015 conf
ICIC (1)
Tian Wang, Keyu Lai, Ce Li, Hichem Snoussi
2014 J jnl
Multim. Tools Appl.
Zhiqiang Tian, Jianru Xue, Xuguang Lan, Ce Li, Nanning Zheng
2014 J jnl
IET Comput. Vis.
Zhiqiang Tian, Nanning Zheng, Jianru Xue, Xuguang Lan, Ce Li, Gang Zhou
2013 J jnl
Sensors
Ce Li, Jianru Xue, Nanning Zheng, Xuguang Lan, Zhiqiang Tian
2012 conf
BMEI
Ce Li, Yannan Zhou, Chengsu Ouyang, Lihua Tian
2011 B conf
ICIP
Zhiqiang Tian, Jianru Xue, Nanning Zheng, Xuguang Lan, Ce Li
2011 J jnl
Signal Process. Image Commun.
Lihua Tian, Nanning Zheng, Jianru Xue, Ce Li, Xiaofeng Wang
2011 C conf
ISCAS
Zhiqiang Tian, Jianru Xue, Ce Li, Xuguang Lan, Nanning Zheng
2011 B conf
ICIP
Ce Li, Jianru Xue, Nanning Zheng, Shaoyi Du, Jihua Zhu, Zhiqiang Tian
2011 A* conf
ACM Multimedia
Zhiqiang Tian, Jianru Xue, Xuguang Lan, Ce Li, Nanning Zheng
2011 A* conf
ACM Multimedia
Ce Li, Jianru Xue, Nanning Zheng, Zhiqiang Tian
2011 J jnl
IEEE Trans. Image Process.
Jianru Xue, Ce Li, Nanning Zheng
2009 B conf
DCC
Xuguang Lan, Nanning Zheng, Jianru Xue, Ce Li, Songlin Zhao
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