C で Py_None を返す前に Py_INCREF(Py_None) が必要なのはなぜですか? 質問する

C で Py_None を返す前に Py_INCREF(Py_None) が必要なのはなぜですか? 質問する

次のように C で Py_None を返す前に Py_INCREF(Py_None) が必要なのはなぜですか?

Py_INCREF(Py_None);
return Py_None;

Py_INCREF(Py_None) を省略すると何が起こりますか?

ベストアンサー1

がないと、Py_INCREFの参照が誤ってカウントされPy_None、インタープリタが を解放する可能性がありますPy_None。はファイルPy_None内で静的に割り当てられているためですObjects/object.c

PyObject _Py_NoneStruct = {
  _PyObject_EXTRA_INIT
  1, &PyNone_Type
};

そしてInclude/object.hそこには定義があります:

#define Py_None (&_Py_NoneStruct)

すると何が起こるかというと、インタープリタが致命的なエラーでクラッシュすることになります。

Fatal Python error: deallocating None

none_deallocこれは次の関数によって生成されますObjects/object.c:

/* ARGUSED */
static void
none_dealloc(PyObject* ignore)
{
    /* This should never get called, but we also don't want to SEGV if
     * we accidentally decref None out of existence.
     */
    Py_FatalError("deallocating None");
}

そのコメントで述べられているように、NoneType独自の割り当て解除関数がない場合、呼び出しはfreeスタック上で行われるため、セグメンテーション違反が発生します。

これをテストするには、次の例をコピーしてください。チュートリアルPy_DECREF(Py_None)関数にの呼び出しを追加し、Noddy_name拡張機能をビルドして、そのメソッドを呼び出すループを実行します。


一般的なケースでは、参照カウントによって0プログラムがさまざまな方法で失敗する可能性があります。

特に、Python は割り当て解除されたオブジェクトが使用するメモリを自由に再利用できるため、オブジェクトへのすべての参照が突然ランダムなオブジェクト (または空のメモリ位置) への参照になる可能性があり、次のようなことが起こる可能性があります。

>>> None   #or whatever object that was deallocated
<ARandomObjectYouNeverSawBefore object at ...>

(これは実際には起こりましたC 拡張機能を書いているときに、時々、いくつかのオブジェクトが ) の呼び出しがないためにランダムに読み取り専用バッファに変わることがありますPy_INCREF

他の状況では、異なる種類のエラーが発生したり、インタープリターがクラッシュしたり、セグメント違反が発生したりする可能性があります。

おすすめ記事