我正在尝试为 CPython 编写一个 Cython 扩展来包装 mcrypt 库,以便我可以将它与 Python 3 一起使用。但是,我在尝试使用其中一个 mcrypt API 时遇到了段错误的问题。
失败的代码是:
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。但是现在我有了一个工作函数,我也将实现一个逐块的方法,这样就可以提供一个可迭代的块用于加密或解密,并且能够在没有整个源代码的情况下做到这一点并同时将所有目标都放在内存中-这样,就可以加密/解密大文件,而不必担心在任何时候在内存中最多保存三个副本...
谢谢大家的帮助!