首页 > 解决方案 > 从 ctypes 访问大内存缓冲区时的段错误

问题描述

在 Python 中访问内存时出现“分段错误(核心转储)”错误,该内存最初是在共享库中分配的。

返回内存的函数声明为:

    extern "C" double *get_sound_data(int desc);
    extern "C" long long get_sound_data_size(int desc);

Python代码是:

from ctypes import *
cdll.LoadLibrary("libsomelib.so")
_lib = CDLL("libsomelib.so")

size = _lib.get_sound_data_size(desc)
data = _lib.get_sound_data(desc)
data = cast(data, POINTER(c_double))
arr = []
for i in range(size):
    arr.append(data[i])

对于小的缓冲区,比如 10k 个项目,它可以工作,但是当库返回几兆字节时,第一次访问尝试,即 Python 段错误中的 data[0]。

我看过这个页面,它看起来很相似https://bugs.python.org/issue13096

我在 Python 2.7.12 和 3.5.2 中遇到同样的错误,操作系统是 Linux。

标签: pythonctypes

解决方案


您不能只是假装默认返回类型很好,并尝试将您得到的无意义结果转换为它应该是的类型。(实际上,Python 可能不应该为此设置默认值,但更改它为时已晚。)默认值是假定 C 函数返回 C int,并且不能保证 C int 的大小与指针; 这些天,它可能不是。

您需要实际设置argtypesrestype能够通过ctypes.

get_sound_data = _lib.get_sound_data
get_sound_data_size = _lib.get_sound_data_size

get_sound_data.argtypes = (ctypes.c_int,)
get_sound_data.restype = ctypes.POINTER(ctypes.c_double)

get_sound_data_size.argtypes = (ctypes.c_int,)
get_sound_data_size.restype = ctypes.c_longlong

# Now use the functions

推荐阅读