5

Python 3 で使用できるように、CPython に Cython 拡張機能を記述して 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

暗号化を行うためのコピーを作成し、次に戻り値への 2 番目のコピーを作成するため、これはおそらく世界で最も効率的なコードではありません。ただし、それを回避できるかどうかはわかりません。新しく割り当てられたバッファを取り、それをバイト文字列としてインプレースで Python に返すことができるかどうかわからないからです。しかし、機能する機能ができたので、ブロックごとの方法も実装して、暗号化または復号化のために反復可能なブロックを提供し、ソース全体がなくても実行できるようにします一度にすべての宛先をメモリ内に保存する---そうすれば、任意の時点で最大3つのコピーをメモリに保持することを心配することなく、巨大なファイルを暗号化/復号化できます...

助けてくれてありがとう、みんな!

4

3 に答える 3

4

char*最初のものはPython 文字列を指しています。2 番目はメモリを割り当てますが、ポインタを Python 文字列に再ポイントし、新しく割り当てられたメモリを無視します。strcpyおそらく、Cython からC ライブラリ関数を呼び出す必要があります。しかし、私は詳細を知りません。

于 2010-12-14T08:23:00.440 に答える
3

コードの改善に役立ついくつかのコメント、私見。Python C API によって提供される関数があり、必要なことを正確に行い、すべてが 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 str オブジェクトを作成しますsource。2 行目は、コピーせずにの内部バッファを指しciphertextています。変更するものは何でも変更します。はまったく新しい Python str であるため、 から返される前に C コードで変更できます。retvalchar *ciphertextretvalretval_real_encrypt

詳細については、上記の関数に関する Python C/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
于 2011-02-21T03:02:35.643 に答える
2

私が (Python 2.x で) 使用したアプローチは、Cython コードがすべての変換と型チェックを自動的に行うように、関数シグネチャで文字列型パラメーターを宣言することです。

def _real_encrypt(self,char* src):
    ...
于 2010-12-14T08:22:28.953 に答える