Python、Cython 和 libmtp 分段错误

问题描述 投票:0回答:1

我无法使用 libmtp 库将 Python 字典作为参数传递给 Cython 函数。

在文件 test.py 中,connect_device() 方法正常工作,连接到设备,并返回映射 LIBMTP_mtpdevice_t 结构的字典,然后我以字典作为参数调用 list_folders() 方法。

我在 C 函数 _list_folders() 内再次将其转换为 LIBMTP_mtpdevice_t 类型,但是当我将其作为参数传递给库函数 LIBMTP_get_folder_list() 时,程序因分段错误而崩溃。

我错过了一些东西,但我不知道是什么。

我希望我说得很清楚,我是 Cython 的新手,希望有人能帮助我找到问题。

谢谢。

测试.py

import mtp_manager as m

def run():
    try:
        print("\nconnecting device...\n")

        dev = m.connect_device()
        print("\ndevice connected listing files and folders...\n")
        lst = m.list_folders(dev)
        print("\n printing list... \n")
        print(f"Folder list: {lst}")
    except Exception as e:
        print(e)

if __name__ == "__main__":
    run()

mtp.pyx

def connect_device():
    dev_d = None
    LIBMTP_Init()
    cdef LIBMTP_mtpdevice_t *device
    device = LIBMTP_Get_First_Device()
    if device is NULL:
        print("No MTP devices found.")
        return None
    try:
        dev_ext = {}
        dev_ext['name'] = device.extensions.name.decode('utf-8')
        dev_ext['major'] = device.extensions.major
        dev_ext['minor'] = device.extensions.minor
        dev_ext['next'] = <uintptr_t> device.extensions.next

        dev_err = {}
        dev_err['errornumber'] = device.errorstack.errornumber
        dev_err['error_text'] = device.errorstack.error_text.decode('utf-8')
        dev_err['next'] = <uintptr_t> device.errorstack.next

        dev_storage = {}
        dev_storage['id'] = device.storage.id
        dev_storage['StorageType'] = device.storage.StorageType
        dev_storage['FilesystemType'] = device.storage.FilesystemType
        dev_storage['AccessCapability'] = device.storage.AccessCapability
        dev_storage['MaxCapacity'] = device.storage.MaxCapacity
        dev_storage['FreeSpaceInBytes'] = device.storage.FreeSpaceInBytes
        dev_storage['FreeSpaceInObjects'] = device.storage.FreeSpaceInObjects
        dev_storage['StorageDescription'] = device.storage.StorageDescription.decode('UTF-8')
        dev_storage['VolumeIdentifier'] = device.storage.VolumeIdentifier.decode('UTF-8')
        dev_storage['next'] = <uintptr_t>device.storage.next
        dev_storage['prev'] = <uintptr_t>device.storage.prev

        dev_d = {}
        dev_d['object_bitsize'] = device.object_bitsize
        dev_d['params'] = <void>device.params
        dev_d['usbinfo'] = <void>device.usbinfo
        dev_d['maximum_battery_level'] = device.maximum_battery_level
        dev_d['default_text_folder'] = device.default_text_folder
        dev_d['default_album_folder'] = device.default_album_folder
        dev_d['default_music_folder'] = device.default_music_folder
        dev_d['default_video_folder'] = device.default_video_folder
        dev_d['default_picture_folder'] = device.default_picture_folder
        dev_d['default_zencast_folder'] = device.default_zencast_folder
        dev_d['default_playlist_folder'] = device.default_playlist_folder
        dev_d['default_organizer_folder'] = device.default_organizer_folder
        dev_d['cd'] = <void>device.cd
        dev_d['cached'] = device.cached
        dev_d['next'] = <uintptr_t>device.next
        dev_d['extensions'] = dev_ext
        dev_d['errorstack'] = dev_err
        dev_d['storage'] = dev_storage

    except Exception as e:
        print(e)
    return dev_d

def list_folders(device):
    folders = _list_folders(<LIBMTP_mtpdevice_t*> device)
    return folders

cdef _list_folders(LIBMTP_mtpdevice_t *device):
    if not device:
      raise TypeError
    cdef LIBMTP_folder_t *folders
    #SEGMENTATION FAULT
    folders = LIBMTP_Get_Folder_List(device)
    ...
python-3.x segmentation-fault cython
1个回答
0
投票

最后我设法自己解决了这个问题:解决方案很简单,只是不处理设备对象,而是将其隐藏在 cython 模块中:

我的 cython 代码:

# mtp_manager.pyx - Cython code to interact with MTP devices
# distutils: language=cython
# cython: language_level=3
import cython
from libmtp cimport LIBMTP_mtpdevice_t, LIBMTP_Get_Folder_List, \
                    LIBMTP_Get_Files_And_Folders, LIBMTP_Get_First_Device, \
                    LIBMTP_Init, LIBMTP_folder_t, LIBMTP_file_t, \
                    LIBMTP_PTP_ObjectHandles, LIBMTP_Get_Folder_List_For_Storage, \
                    LIBMTP_device_extension_t, LIBMTP_error_t, LIBMTP_error_number_t, \
                    LIBMTP_devicestorage_t
from libc.stdint cimport uint32_t, uint16_t, uint64_t, uint8_t, uintptr_t, int

class FileManager(cFileManager):
  def __init__(self):
    super().__init__()

cdef class cFileManager:
  cdef LIBMTP_mtpdevice_t * __device
  def __init__(self):
      self.__device = self.connect_device()
      if not self.__device:
          raise TypeError

  cdef LIBMTP_mtpdevice_t * connect_device(self):
      LIBMTP_Init()
      cdef LIBMTP_mtpdevice_t *device
      return LIBMTP_Get_First_Device()

  def list_folders(self):
      return self._list_folders()

  cdef _list_folders(self):
      cdef LIBMTP_folder_t * folders = LIBMTP_Get_Folder_List(self.__device)
      lst = []
      while folders:
        lst.append(folders.name.decode('UTF-8'))
        folders = folders.sibling
      return lst

Python代码:

    from mtp_file_manager import FileManager

def run():
    try:
        print("\nconnecting device...\n")
        fm = FileManager()
        print("\ndevice connected listing files and folders...\n")
        print("\n printing list... \n")
        print(fm.list_folders())
    except Exception as e:
        print(e)

if __name__ == "__main__":
    run()

我希望它对其他人有用

© www.soinside.com 2019 - 2024. All rights reserved.