From bdf5f5501b00edf962ad58af0c9ce2bc8f54c23e Mon Sep 17 00:00:00 2001 From: Luke Craig Date: Fri, 13 Mar 2026 11:40:40 -0400 Subject: [PATCH 1/3] new tests --- tests/test_deep_init.py | 98 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 tests/test_deep_init.py diff --git a/tests/test_deep_init.py b/tests/test_deep_init.py new file mode 100644 index 0000000..da55c27 --- /dev/null +++ b/tests/test_deep_init.py @@ -0,0 +1,98 @@ +import pytest +from dwarffi import DFFI + +def test_deep_initialization_syscall_hook(): + """ + Verifies that dwarffi can recursively initialize a complex struct containing + nested structs, string arrays, and arrays of structs using a standard Python dict. + """ + isf = { + "metadata": {}, + "base_types": { + "int": {"kind": "int", "size": 4, "signed": True, "endian": "little"}, + "long": {"kind": "int", "size": 8, "signed": True, "endian": "little"}, + "bool": {"kind": "int", "size": 1, "signed": False, "endian": "little"}, + "char": {"kind": "int", "size": 1, "signed": False, "endian": "little"}, + }, + "user_types": { + "value_filter": { + "kind": "struct", "size": 40, + "fields": { + "enabled": {"offset": 0, "type": {"kind": "base", "name": "bool"}}, + "type": {"offset": 4, "type": {"kind": "base", "name": "int"}}, + "value": {"offset": 8, "type": {"kind": "base", "name": "long"}}, + "min_value": {"offset": 16, "type": {"kind": "base", "name": "long"}}, + "max_value": {"offset": 24, "type": {"kind": "base", "name": "long"}}, + "bitmask": {"offset": 32, "type": {"kind": "base", "name": "long"}}, + } + }, + "syscall_hook": { + "kind": "struct", "size": 336, + "fields": { + "enabled": {"offset": 0, "type": {"kind": "base", "name": "bool"}}, + "on_enter": {"offset": 1, "type": {"kind": "base", "name": "bool"}}, + "name": { + "offset": 2, + "type": {"kind": "array", "count": 16, "subtype": {"kind": "base", "name": "char"}} + }, + "filter_pid": {"offset": 20, "type": {"kind": "base", "name": "int"}}, + "retval_filter": {"offset": 24, "type": {"kind": "struct", "name": "value_filter"}}, + "arg_filters": { + "offset": 64, + "type": {"kind": "array", "count": 6, "subtype": {"kind": "struct", "name": "value_filter"}} + } + } + } + }, + "enums": {}, "symbols": {} + } + ffi = DFFI(isf) + + # The structured dict we want to pass + init_data = { + "enabled": True, + "on_enter": False, + "name": "sys_open", + "filter_pid": 1337, + "retval_filter": { + "enabled": True, + "type": 0, + "value": -1, # Expecting an error + "min_value": 0, + "max_value": 0, + "bitmask": 0 + }, + "arg_filters": [ + # Arg 0 + {"enabled": True, "type": 1, "value": 0, "min_value": 10, "max_value": 20, "bitmask": 0}, + # Arg 1 + {"enabled": False, "type": 0, "value": 0, "min_value": 0, "max_value": 0, "bitmask": 0}, + # We omit the rest, expecting them to safely default to 0 + ] + } + + # Initialize it all in one go + sch = ffi.new("struct syscall_hook", init_data) + + # 1. Assert basic primitives (bools return 1 or 0 as C-ints) + assert sch.enabled == 1 + assert sch.on_enter == 0 + assert sch.filter_pid == 1337 + + # 2. Assert string assignment + assert ffi.string(sch.name) == b"sys_open" + + # 3. Assert nested struct + assert sch.retval_filter.enabled == 1 + assert sch.retval_filter.value == -1 + + # 4. Assert array of structs + assert sch.arg_filters[0].enabled == 1 + assert sch.arg_filters[0].min_value == 10 + assert sch.arg_filters[0].max_value == 20 + + assert sch.arg_filters[1].enabled == 0 + + # 5. Assert omitted array elements default to zeroed memory safely + assert sch.arg_filters[2].enabled == 0 + assert sch.arg_filters[5].value == 0 \ No newline at end of file From 04d327a88ef83b19f6dd7053f0d2d8043c93b55b Mon Sep 17 00:00:00 2001 From: Luke Craig Date: Fri, 13 Mar 2026 11:43:25 -0400 Subject: [PATCH 2/3] dffi: fix casting behavior --- src/dwarffi/dffi.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/dwarffi/dffi.py b/src/dwarffi/dffi.py index 096d7d3..4c42a52 100644 --- a/src/dwarffi/dffi.py +++ b/src/dwarffi/dffi.py @@ -652,13 +652,20 @@ def cast(self, ctype: Union[str, Vtype], value: Any) -> BoundType: The newly typed BoundTypeInstance or Ptr. """ t = self._typeof_or_raise(ctype) + is_target_pointer = isinstance(t, dict) and t.get("kind") == "pointer" + + if isinstance(value, Ptr): + value = value.address + elif isinstance(value, BoundTypeInstance) and is_target_pointer: + # Allow casting structs directly to pointers + value = self.addressof(value).address # Casting an integer to a pointer if isinstance(value, int): - if isinstance(t, dict) and t.get("kind") == "pointer": + if is_target_pointer: return Ptr(value, t.get("subtype"), self) - if hasattr(t, "size"): + if hasattr(t, "size") and t.size is not None: buf = bytearray(t.size) else: buf = bytearray(8) From c0853779f10c486792a3d5ee9804e4f066155e22 Mon Sep 17 00:00:00 2001 From: Luke Craig Date: Fri, 13 Mar 2026 11:48:42 -0400 Subject: [PATCH 3/3] ruff --- tests/test_deep_init.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_deep_init.py b/tests/test_deep_init.py index da55c27..347be60 100644 --- a/tests/test_deep_init.py +++ b/tests/test_deep_init.py @@ -1,6 +1,6 @@ -import pytest from dwarffi import DFFI + def test_deep_initialization_syscall_hook(): """ Verifies that dwarffi can recursively initialize a complex struct containing