James Abello

59 papers A* 1A 6B 8C 4Misc 1Journal 23Unranked 14
YearRankTypeTitle / Venue / Authors
2024 C conf
DATA
James Abello, Timothy R. Tangherlini, Haoyang Zhang
2023 conf
EDBT/ICDT Workshops
James Abello, Haoyang Zhang
2022 J jnl
IEEE Computer Graphics and Applications
James Abello, Haoyang Zhang, Daniel Nakhimovich, Chengguizi Han, Mridul Aanjaneya
2022 J jnl
Big Data Res.
James Abello, Daniel Nakhimovich
2021 conf
EDBT/ICDT Workshops
James Abello, Daniel Nakhimovich, Chengguizi Han, Mridul Aanjaneya
2020 conf
EDBT/ICDT Workshops
James Abello, Daniel Nakhimovich
2019 A conf
IUI
James Abello, Fred Hohman, Varun Bezzam, Duen Horng Chau
2019 ch.
Business and Consumer Analytics: New Ideas
James Abello, Daniel Mawhirter, Kevin Sun
2018 J jnl
CoRR
James Abello, Fred Hohman, Varun Bezzam, Duen Horng Chau
2017 A conf
SDM
Robert S. Pienta, Minsuk Kahng, Zhiyuan Lin, Jilles Vreeken, Partha P. Talukdar, James Abello, Ganesh Parameswaran, Duen Horng Chau
2017 J jnl
Theor. Comput. Sci.
James Abello, Pavel Klavík, Jan Kratochvíl, Tomás Vyskocil
2015 conf
ICDM Workshops
Brian Thompson, James Abello
2015 conf
BigComp
Robert S. Pienta, James Abello, Minsuk Kahng, Duen Horng Chau
2015 J jnl
CoRR
Robert S. Pienta, Zhiyuan Lin, Minsuk Kahng, Jilles Vreeken, Partha P. Talukdar, James Abello, Ganesh Parameswaran, Duen Horng Chau
2014 J jnl
IEEE Trans. Vis. Comput. Graph.
James Abello, Steffen Hadlak, Heidrun Schumann, Hans-Jörg Schulz
2014 J jnl
Soc. Netw. Anal. Min.
James Abello, François Queyroi
2013 B conf
ASONAM
James Abello, François Queyroi
2013 conf
Multivariate Network Visualization
Daniel Archambault, James Abello, Jessie Kennedy, Stephen G. Kobourov, Kwan-Liu Ma, Silvia Miksch, Chris Muelder, Alexandru C. Telea
2012 J jnl
Commun. ACM
James Abello, Peter Broadwell, Timothy R. Tangherlini
2012 B conf
IPEC
James Abello, Pavel Klavík, Jan Kratochvíl, Tomás Vyskocil
2012 J jnl
CoRR
James Abello, Pavel Klavík, Jan Kratochvíl, Tomás Vyskocil
2010 A* conf
ICDM
James Abello, Tina Eliassi-Rad, Nishchal Devanur
2009 J jnl
Comput. Graph.
Christian Tominski, James Abello, Heidrun Schumann
2006 J jnl
IEEE Trans. Vis. Comput. Graph.
James Abello, Frank van Ham, Neeraj Krishnan
2006 C conf
IV
Christian Tominski, James Abello, Frank van Ham, Heidrun Schumann
2005 ed.
Discrete Methods in Epidemiology
James Abello, Graham Cormode
2004 Misc conf
SAC
Christian Tominski, James Abello, Heidrun Schumann
2004 J jnl
J. Univers. Comput. Sci.
James Abello, Alex J. Pogel, Lance Miller
2004 conf
Discrete Methods in Epidemiology
James Abello, Alex J. Pogel
2004 J jnl
Comput. Graph.
James Abello
2004 conf
INFOVIS
James Abello, Frank van Ham
2004 conf
Discrete Methods in Epidemiology
James Abello, Michael Capalbo
2004 conf
Discrete Methods in Epidemiology
James Abello, Graham Cormode, Dmitriy Fradkin, David Madigan, Ofer Melnik, Ilya B. Muchnik
2004 A conf
GD
James Abello, Stephen G. Kobourov, Roman Yusufov
2003 A conf
CIKM
James Abello, Yannis Kotidis
2002 J jnl
Algorithmica
James Abello, Adam L. Buchsbaum, Jeffery R. Westbrook
2002 B conf
SPAA
Jop F. Sibeyn, James Abello, Ulrich Meyer
2002 J jnl
IEEE Trans. Vis. Comput. Graph.
James Abello, Jeffrey L. Korn
2002 B conf
LATIN
James Abello, Mauricio G. C. Resende, Sandra Sudarsky
2002 B conf
AVI
James Abello, Jeffrey L. Korn, Matthias Kreuseler
2002 J jnl
Discret. Comput. Geom.
James Abello, Krishna Kumar
2001 J jnl
J. Glob. Optim.
James Abello, Sergiy Butenko, Panos M. Pardalos, Mauricio G. C. Resende
2001 conf
INFOVIS
James Abello, Irene Finocchi, Jeffrey L. Korn
2000 conf
INFOVIS
James Abello, Jeffrey L. Korn
1998 A conf
ESA
James Abello, Adam L. Buchsbaum, Jeffery R. Westbrook
1998 J jnl
Int. J. Comput. Geom. Appl.
James Abello, Vladimir Estivill-Castro, Thomas C. Shermer, Jorge Urrutia
1998 conf
External Memory Algorithms
James Abello, Panos M. Pardalos, Mauricio G. C. Resende
1998 B conf
LATIN
James Abello, Emden R. Gansner
1997 J jnl
Theor. Comput. Sci.
James Abello, Shlomi Dolev
1995 B conf
ISAAC
James Abello, Vladimir Estivill-Castro, Thomas C. Shermer, Jorge Urrutia
1995 B conf
LATIN
James Abello, Krishna Kumar
1995 J jnl
Discret. Comput. Geom.
James Abello, Ömer Egecioglu, Krishna Kumar
1994 A conf
GD
James Abello, Krishna Kumar
1993 C conf
ICCI
James Abello, Krishna Kumar, Ömer Egecioglu
1993 C conf
ICCI
James Abello, Anne Houang, James Russell
1993 J jnl
Int. J. Comput. Geom. Appl.
James Abello, Ömer Egecioglu
1992 conf
Computational Support for Discrete Mathematics
James Abello, Sandra Sudarsky, T. Veatch, J. Waller
1991 J jnl
Australas. J Comb.
James Abello, Michael R. Fellows, John Stillwell
1991 J jnl
SIAM J. Discret. Math.
James Abello
tests/unit/test_smali_normalization.py
← Index tests/unit/test_smali_normalization.py python
"""Unit tests for smali semantic normalization.

Tests the three normalization levels (category, opcode, opcode_api),
opcode categorization, ACFG feature index mapping, and integration
with MinHash computation.
"""
import pytest

pytestmark = [pytest.mark.unit, pytest.mark.apk, pytest.mark.decompile]


class TestCategorizeOpcode:
    """Tests for opcode -> semantic category mapping."""

    def test_arithmetic(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("add-int") == "ALU"
        assert categorize_opcode("mul-long/2addr") == "ALU"
        assert categorize_opcode("neg-int") == "ALU"

    def test_data_movement(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("move-result") == "MOV"
        assert categorize_opcode("const/4") == "CONST"
        assert categorize_opcode("const-string") == "CONST"

    def test_memory_access(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("iget-object") == "LOAD"
        assert categorize_opcode("sput-wide") == "STORE"
        assert categorize_opcode("aget-byte") == "LOAD"

    def test_invocation(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("invoke-virtual") == "CALL"
        assert categorize_opcode("invoke-static") == "CALL"
        assert categorize_opcode("invoke-direct") == "CALL"

    def test_control_flow(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("if-eqz") == "BRANCH"
        assert categorize_opcode("goto") == "JMP"
        assert categorize_opcode("goto/16") == "JMP"
        assert categorize_opcode("return-void") == "RET"

    def test_comparison(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("cmp-long") == "CMP"
        assert categorize_opcode("cmpl-float") == "CMP"
        assert categorize_opcode("cmpg-double") == "CMP"

    def test_conversion(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("int-to-long") == "CONV"
        assert categorize_opcode("float-to-int") == "CONV"

    def test_object_type(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("new-instance") == "ALLOC"
        assert categorize_opcode("check-cast") == "TYPE"
        assert categorize_opcode("instance-of") == "TYPE"

    def test_exception_sync(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("throw") == "EXC"
        assert categorize_opcode("monitor-enter") == "SYNC"

    def test_unknown(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("nop") == "OTHER"


class TestNormalizeInstruction:
    """Tests for single instruction normalization at various levels."""

    def test_category_level(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        assert normalize_instruction("add-int v0, v1, v2", "category") == "ALU"
        assert normalize_instruction("invoke-virtual {p0}, Lcom/Foo;->bar()V", "category") == "CALL"
        assert normalize_instruction("return-void", "category") == "RET"

    def test_opcode_level_strips_width(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        # Width variants collapse to same base
        assert normalize_instruction("add-int v0, v1, v2", "opcode") == "add"
        assert normalize_instruction("add-long v0, v2, v4", "opcode") == "add"
        assert normalize_instruction("add-float v0, v1, v2", "opcode") == "add"
        # Addressing modes collapse too
        assert normalize_instruction("add-int/2addr v0, v1", "opcode") == "add"

    def test_opcode_api_invoke(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            "invoke-virtual {p0, v0}, Lcom/example/Foo;->bar(I)V"
        )
        assert result == "CALL Lcom/example/Foo;->bar(I)V"

    def test_opcode_api_invoke_no_ref(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        # If somehow no method ref is found, fallback to CALL
        assert normalize_instruction("invoke-virtual {v0}") == "CALL"

    def test_opcode_api_field_load(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            "iget-object v0, p0, Lcom/Foo;->mField:Ljava/lang/String;"
        )
        assert result == "LOAD Lcom/Foo;->mField:Ljava/lang/String;"

    def test_opcode_api_field_store(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            "iput-object v0, p0, Lcom/Foo;->mField:Ljava/lang/String;"
        )
        assert result == "STORE Lcom/Foo;->mField:Ljava/lang/String;"

    def test_opcode_api_androguard_field_format(self):
        """androguard uses space instead of colon in field references."""
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            "iget-object v0, p0, Lcom/Foo;->mField Ljava/lang/String;"
        )
        assert result.startswith("LOAD")
        assert "Lcom/Foo;->mField" in result

    def test_opcode_api_new_instance(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            "new-instance v0, Lcom/example/MyClass;"
        )
        assert result == "ALLOC Lcom/example/MyClass;"

    def test_opcode_api_const_string(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            'const-string v0, "hello world"'
        )
        assert result == 'CONST_STR "hello world"'

    def test_opcode_api_const_string_jumbo(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            'const-string/jumbo v0, "large string"'
        )
        assert result == 'CONST_STR "large string"'

    def test_opcode_api_fallback_to_category(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        # Non-special instructions fall back to category
        assert normalize_instruction("add-int v0, v1, v2") == "ALU"
        assert normalize_instruction("return-void") == "RET"
        assert normalize_instruction("nop") == "OTHER"

    def test_empty_input(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        assert normalize_instruction("") == ""
        assert normalize_instruction("   ") == ""


class TestNormalizeMethodBody:
    """Tests for full method body normalization."""

    def test_filters_directives_labels_comments(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_method_body
        body = """\
.locals 2
# comment
:label_0
add-int v0, v1, v2
.line 42
invoke-virtual {p0}, Lcom/Foo;->bar()V
return-void
"""
        result = normalize_method_body(body, "category")
        assert result == ["ALU", "CALL", "RET"]

    def test_opcode_api_preserves_api_refs(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_method_body
        body = """\
const/4 v0, 0x0
invoke-virtual {p0, v0}, Lcom/Foo;->setX(I)V
iget-object v1, p0, Lcom/Foo;->name:Ljava/lang/String;
return-void
"""
        result = normalize_method_body(body, "opcode_api")
        assert result[0] == "CONST"
        assert result[1] == "CALL Lcom/Foo;->setX(I)V"
        assert result[2] == "LOAD Lcom/Foo;->name:Ljava/lang/String;"
        assert result[3] == "RET"

    def test_empty_body(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_method_body
        assert normalize_method_body("") == []
        assert normalize_method_body("\n\n") == []


class TestNormalizationWithMinHash:
    """Integration tests: normalization + MinHash computation."""

    def test_minhash_returns_signature(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        body = """\
const/4 v0, 0x0
invoke-virtual {p0, v0}, Lcom/Foo;->bar(I)V
iget-object v1, p0, Lcom/Foo;->name:Ljava/lang/String;
add-int v2, v0, v1
return-void
"""
        sig = compute_minhash(body)
        assert sig is not None
        assert len(sig) == 64
        assert all(0 <= v < 256 for v in sig)

    def test_minhash_register_invariance(self):
        """Same operations with different registers should produce identical signatures."""
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        body_a = """\
const/4 v0, 0x0
invoke-virtual {p0, v0}, Lcom/Foo;->bar(I)V
iget-object v1, p0, Lcom/Foo;->name:Ljava/lang/String;
add-int v2, v0, v1
return-void
"""
        body_b = """\
const/4 v3, 0x0
invoke-virtual {p1, v3}, Lcom/Foo;->bar(I)V
iget-object v4, p1, Lcom/Foo;->name:Ljava/lang/String;
add-int v5, v3, v4
return-void
"""
        sig_a = compute_minhash(body_a)
        sig_b = compute_minhash(body_b)
        assert sig_a == sig_b

    def test_minhash_width_invariance(self):
        """Width variants of same operations should produce identical signatures."""
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        body_int = """\
add-int v0, v1, v2
sub-int v3, v0, v1
mul-int v4, v0, v3
return v4
"""
        body_long = """\
add-long v0, v2, v4
sub-long v6, v0, v2
mul-long v8, v0, v6
return-wide v8
"""
        sig_int = compute_minhash(body_int)
        sig_long = compute_minhash(body_long)
        # Both normalize to ALU, ALU, ALU, RET -> identical
        assert sig_int == sig_long

    def test_minhash_different_apis_differ(self):
        """Methods calling different APIs should produce different signatures."""
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        body_a = """\
const/4 v0, 0x0
invoke-virtual {p0, v0}, Lcom/crypto/AES;->encrypt([B)[B
invoke-virtual {v0}, Ljava/io/OutputStream;->write([B)V
return-void
"""
        body_b = """\
const/4 v0, 0x0
invoke-virtual {p0, v0}, Ljava/lang/String;->length()I
invoke-virtual {v0}, Ljava/io/PrintStream;->println(I)V
return-void
"""
        sig_a = compute_minhash(body_a)
        sig_b = compute_minhash(body_b)
        assert sig_a != sig_b

    def test_minhash_too_few_instructions(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        assert compute_minhash("return-void\nnop") is None


class TestACFGBlockFeatures:
    """Tests for per-block ACFG feature extraction via smali_cfg."""

    def test_simple_linear_method(self):
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        body = """\
add-int v0, v1, v2
invoke-virtual {p0}, Lcom/Foo;->bar()V
return-void
"""
        metrics = compute_cfg_metrics(body)
        assert metrics.block_count >= 1
        assert len(metrics.block_features) == metrics.block_count
        # Each feature vector has 8 elements
        for feat in metrics.block_features:
            assert len(feat) == 8

    def test_branching_method_has_multiple_blocks(self):
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        body = """\
const/4 v0, 0x0
if-eqz v0, :cond_0
invoke-virtual {p0}, Lcom/Foo;->a()V
goto :goto_0
:cond_0
invoke-virtual {p0}, Lcom/Foo;->b()V
:goto_0
return-void
"""
        metrics = compute_cfg_metrics(body)
        assert metrics.block_count >= 3
        assert len(metrics.block_features) == metrics.block_count

    def test_feature_vector_arithmetic_count(self):
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        body = """\
add-int v0, v1, v2
sub-int v3, v0, v1
mul-int v4, v0, v3
return v4
"""
        metrics = compute_cfg_metrics(body)
        assert len(metrics.block_features) == 1
        feat = metrics.block_features[0]
        # feat[0] = instr_count (4), feat[1] = arithmetic (3)
        assert feat[0] == 4
        assert feat[1] >= 3  # 3 ALU ops

    def test_feature_vector_call_count(self):
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        body = """\
invoke-virtual {p0}, Lcom/A;->a()V
invoke-static {v0}, Lcom/B;->b()V
return-void
"""
        metrics = compute_cfg_metrics(body)
        feat = metrics.block_features[0]
        # feat[4] = call count
        assert feat[4] == 2