Cython 字节到 C char*

Mic*_*sch 5 python cython python-3.x python-bindings

我正在尝试为 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
Run Code Online (Sandbox Code Playgroud)

现在,按照我理解 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
Run Code Online (Sandbox Code Playgroud)

它仍然因段错误而崩溃。它在 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
Run Code Online (Sandbox Code Playgroud)

它可能不是世界上最高效的代码,因为它先复制一份以进行加密,然后再复制一份返回值。不过,我不确定是否可以避免这种情况,因为我不确定是否可以采用新分配的缓冲区并将其作为字节串原地返回给 Python。但是现在我有了一个工作函数,我也将实现一个逐块的方法,这样人们就可以提供一个可迭代的块来加密或解密,并且能够在没有整个源的情况下做到这一点并一次性将所有目标都存储在内存中——这样,就可以加密/解密大文件,而不必担心在任何时候在内存中最多保留三个副本......

谢谢大家的帮助!

Kar*_*tel 4

第一个指向char*Python 字符串。第二个分配内存,但随后将指针重新指向 Python 字符串并忽略新分配的内存。您应该strcpy从 Cython 调用 C 库函数;但我不知道细节。