From 38eac6c36e60f4b4bcccde44f02a318465ed55a0 Mon Sep 17 00:00:00 2001 From: Mark Rowe Date: Mon, 28 Sep 2026 23:57:01 -0700 Subject: [PATCH] Release the type library reference returned when importing a library type or object `BNBinaryViewImportTypeLibraryType` and `BNBinaryViewImportTypeLibraryObject` store a new reference to the library the type or object came from in their `lib` out-parameter. The Python and Rust wrappers never released it, so every import leaked a reference to a type library. The Python wrappers also pointed the out-parameter at the caller's own handle, which let core write into the caller's `TypeLibrary`. Now both bindings pass a separate out-parameter and release what core returns. The C++ API already handled this correctly. --- python/binaryview.py | 22 ++++++++++++---------- rust/src/binary_view.rs | 8 ++++++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/python/binaryview.py b/python/binaryview.py index f2ca94319f..ffe1500910 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -9200,15 +9200,16 @@ def import_library_type(self, name: str, lib: Optional[typelibrary.TypeLibrary] :rtype: Type """ _name = _types.QualifiedName(name) - _lib = ctypes.POINTER(ctypes.POINTER(core.BNTypeLibrary))() + _lib = ctypes.POINTER(core.BNTypeLibrary)() if lib is not None: - _lib.contents = lib.handle - else: - _lib.contents = ctypes.POINTER(core.BNTypeLibrary)() + _lib = ctypes.cast(lib.handle, ctypes.POINTER(core.BNTypeLibrary)) handle = core.BNBinaryViewImportTypeLibraryType( - self.handle, _lib, _name._to_core_struct() + self.handle, ctypes.byref(_lib), _name._to_core_struct() ) + # Core stores a new reference to the library the type came from in `_lib`. + if _lib: + core.BNFreeTypeLibrary(_lib) if handle is None: return None return _types.Type.create(handle, platform=self.platform) @@ -9255,15 +9256,16 @@ def import_library_object(self, name: str, lib: Optional[typelibrary.TypeLibrary :rtype: Type """ _name = _types.QualifiedName(name) - _lib = ctypes.POINTER(ctypes.POINTER(core.BNTypeLibrary))() + _lib = ctypes.POINTER(core.BNTypeLibrary)() if lib is not None: - _lib.contents = lib.handle - else: - _lib.contents = ctypes.POINTER(core.BNTypeLibrary)() + _lib = ctypes.cast(lib.handle, ctypes.POINTER(core.BNTypeLibrary)) handle = core.BNBinaryViewImportTypeLibraryObject( - self.handle, _lib, _name._to_core_struct() + self.handle, ctypes.byref(_lib), _name._to_core_struct() ) + # Core stores a new reference to the library the object came from in `_lib`. + if _lib: + core.BNFreeTypeLibrary(_lib) if handle is None: return None return _types.Type.create(handle, platform=self.platform) diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index c6689bdf02..9a8efcf507 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -2804,6 +2804,10 @@ impl BinaryView { let result = unsafe { BNBinaryViewImportTypeLibraryType(self.handle, &mut lib_ref, &mut raw_name) }; QualifiedName::free_raw(raw_name); + // Core stores a new reference to the library the type came from in `lib_ref`. + if let Some(lib_ref) = NonNull::new(lib_ref) { + drop(unsafe { TypeLibrary::ref_from_raw(lib_ref) }); + } (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) }) } @@ -2831,6 +2835,10 @@ impl BinaryView { BNBinaryViewImportTypeLibraryObject(self.handle, &mut lib_ref, &mut raw_name) }; QualifiedName::free_raw(raw_name); + // Core stores a new reference to the library the object came from in `lib_ref`. + if let Some(lib_ref) = NonNull::new(lib_ref) { + drop(unsafe { TypeLibrary::ref_from_raw(lib_ref) }); + } (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) }) }