我正在尝试为CPython编写一个Cython扩展来包装mcrypt库,这样我就可以在Python3中使用它了。但是,我遇到了一个问题,在使用mcrypt时,我遇到了分段错误。
失败的代码是:
def _real_encrypt(self, source):
src_len = len(source)
cdef char* ciphertext = source
cmc.mcrypt_generic(self._mcStream, <void *>ciphertext, src_len)
retval = source[:src_len]
return retval现在,按照我理解Cython文档的方式,第3行的赋值应该将缓冲区( Python 3中的一个对象)的内容复制到C字符串指针。我想这也意味着它会分配内存,但是当我做这个修改时:
def _real_encrypt(self, source):
src_len = len(source)
cdef char* ciphertext = <char *>malloc(src_len)
ciphertext = source
cmc.mcrypt_generic(self._mcStream, <void *>ciphertext, src_len)
retval = source[:src_len]
return retval它还是有段故障坠毁了。它在mcrypt_generic内部崩溃了,但是当我使用普通的C代码时,我能够很好地工作,所以我对Cython在这里是如何处理C数据的肯定不太了解。
谢谢你的帮助!
ETA:问题是我的问题。我是在醒了好几个小时之后才开始做这件事的(这不是我们都做过的吗?)错过了一些愚蠢的东西。我现在拥有的代码是:
def _real_encrypt(self, source):
src_len = len(source)
cdef char *ciphertext = <char *>malloc(src_len)
cmc.strncpy(ciphertext, source, src_len)
cmc.mcrypt_generic_init(self._mcStream, <void *>self._key,
len(self._key), NULL)
cmc.mcrypt_generic(self._mcStream, <void *>ciphertext,
src_len)
retval = ciphertext[:src_len]
cmc.mcrypt_generic_deinit(self._mcStream)
return retval它可能不是世界上最有效的代码,因为它生成一个副本来进行加密,然后再复制到返回值。不过,我不确定是否有可能避免这种情况,因为我不确定是否有可能将新分配的缓冲区作为字节字符串返回到Python就地。但是现在我有了一个工作函数,我也要实现一个块的方法,这样我们就可以提供一个可迭代的块来进行加密或解密,并且能够做到这一点,而不必同时将整个源和目的地都存储在内存中--这样,就可以加密/解密巨大的文件,而不必担心在任何一个点将其保存在内存中最多三个副本.
谢谢大家的帮助!
发布于 2010-12-14 08:23:00
第一个是将char*指向Python。第二个分配内存,但随后重新指向指向Python字符串的指针,并忽略新分配的内存。您应该从Cython调用C库函数strcpy;但我不知道细节。
发布于 2011-02-21 03:02:35
对您的代码进行一些评论,以帮助改进它,IMHO。python提供的一些函数完全可以完成您需要做的事情,并确保所有操作都符合Python的操作方式。它将处理嵌入式NULL,而不存在任何问题。
与其直接调用malloc,不如更改如下:
cdef char *ciphertext = <char *>malloc(src_len)至
cdef str retval = PyString_FromStringAndSize(PyString_AsString(source), <Py_ssize_t>src_len)
cdef char *ciphertext = PyString_AsString(retval)上面的行将创建一个全新的Python对象,该对象初始化为source的内容。第二行将ciphertext指向retval的内部char *缓冲区,而不进行复制。任何修改ciphertext的内容都会修改retval。由于retval是全新的Python,所以在从_real_encrypt返回之前,可以用C代码对其进行修改。
有关更多细节,这里和这里,请参阅上述函数的Python /API文档。
净效果为您节省了一份副本。整个代码将类似于:
cdef extern from "Python.h":
object PyString_FromStringAndSize(char *, Py_ssize_t)
char *PyString_AsString(object)
def _real_encrypt(self, source):
src_len = len(source)
cdef str retval = PyString_FromStringAndSize(PyString_AsString(source), <Py_ssize_t>src_len)
cdef char *ciphertext = PyString_AsString(retval)
cmc.mcrypt_generic_init(self._mcStream, <void *>self._key,
len(self._key), NULL)
cmc.mcrypt_generic(self._mcStream, <void *>ciphertext,
src_len)
# since the above initialized ciphertext, the retval str is also correctly initialized, too.
cmc.mcrypt_generic_deinit(self._mcStream)
return retval发布于 2010-12-14 08:22:28
我使用的方法(使用Python2.x)是在函数签名中声明字符串类型参数,以便Cython代码自动完成所有转换和类型检查:
def _real_encrypt(self,char* src):
...https://stackoverflow.com/questions/4436857
复制相似问题