0

私は専用のLinuxCentOSシステムでうまく機能しているプロジェクトに取り組んできました。

一般的な考え方は、ctypesを使用してCで記述された共有ライブラリを呼び出すPythonワークフローマネージャーがあるということです。正常に動作します。

ただし、開発目的でプロジェクトのローカルインスタンスを用意する必要があります。Windows7でVMWareを使用してLinuxMint仮想マシンをセットアップしました。ほとんどの場合、すべてが正常に機能します。

問題は、共有ライブラリの1つで関数を呼び出すと、1つのモジュールがセグメンテーション違反でクラッシュすることです。通常、これは問題ありません。専用のLinuxマシンでは、「gdb python corename」のようなものを使用すると、クラッシュした場所を正確に確認して問題を解決できます。

ただし、ローカル設定では問題が発生します。私が最も気付くのは、GDBが正しいメモリアドレスを報告しないことです。これは巨大なプロジェクトなので、すべてのコードを投稿することはできませんが、概要を説明します。

Pythonモジュールは、文字列である「file_path」変数を作成します。まず、これを特定の共有ライブラリに渡してファイルをロードします。コマンドを実行すると、Pythonで

hex(id(file_path))

'46cb4ec'のようなものを返します。最初の共有ライブラリであるCでは、最初に

printf("file_pathaddress = %x\n", &file_path[0]);

'file_path address = 46cb4ec'を出力します。これは、Pythonの' id()'関数を介して取得したものと同じです。これは予想されることだと思います...?

とにかく..これと同じ変数を別の共有ライブラリに送信しましたが、この呼び出しですぐにクラッシュします。コアファイルを分析すると、関数内の行ではなく、関数呼び出し自体でクラッシュすることがわかります。ただし、奇妙なことに、次のような出力が表示されます。

Program terminated with signal 11, Segmentation fault.
#0  0x00007f124448c9fc in seam_processor (irm_filename=<error reading variable: Cannot access memory at address 0x7fff5fab51b8>, 
seam_data_path=<error reading variable: Cannot access memory at address 0x7fff5fab51b0>, 
    full_data_path=<error reading variable: Cannot access memory at address 0x7fff5fab51a8>, ranges=<error reading variable: Cannot access memory at address 0x7fff5fab51a0>, 
    job_id=<error reading variable: Cannot access memory at address 0x7fff5fab519c>, job_owner=<error reading variable: Cannot access memory at address 0x7fff5fab5198>, 
    y_tile_in=1, x_tile_in=1, fc_int=10650000000, atmos_props=..., surf_props=..., extra_props=<error reading variable: Cannot access memory at address 0x7fff5fab5190>, 
    gascalc_ftype=513, len_gas_sectrum=16, vect_spec_fq=<error reading variable: Cannot access memory at address 0x7fff5fab5188>, surfscat_theta_inc_vector_size=6, 
    surfscat_theta_inc_vector=<error reading variable: Cannot access memory at address 0x7fff5fab5180>, surfscat_phi_inc_vector_size=6, 
    surfscat_phi_inc_vector=<error reading variable: Cannot access memory at address 0x7fff5fab5178>, surfscat_theta_scat_vector_size=6, 
    surfscat_theta_scat_vector=<error reading variable: Cannot access memory at address 0x7fff5fab5170>, surfscat_phi_scat_vector_size=6, 
    surfscat_phi_scat_vector=<error reading variable: Cannot access memory at address 0x7fff5fab5168>) at src/seam_processor.c:47

したがって、私が理解できないのは、GDBがこれらのメモリアドレスをそのように報告している理由です。この場合、「irm_filename」変数はPythonが「file_path」として渡したものであるため、そのアドレスは他のライブラリとid()関数が報告する0x46CB4ECである必要があります。なぜ違うのですか?ただし、奇妙なことに、「y_tile_in」のように、一部の変数は問題ありません。gdbで行う場合:

(gdb) print &y_tile_in
$1 = (int *) 0x7fff60543f80

したがって、このメモリアドレスを読み取ることはできますが、これはPythonのid()が報告するもの、またはアドレスの同様のC printf()がクラッシュしないライブラリで報告するものと同じではありません。また、これらのメモリアドレスは本当に大きな数であり、私が持っているメモリの量よりもはるかに大きいです...それらは実際にはどういう意味ですか?

それでは、私の質問は、ここで正確に何が起こっているのかということです。これを実行している仮想マシンでこれが実行されているという事実はありますか?マッピングは行われていますか?仮想マシンでgdbを使用する場合にやらなければならないことについて、オンラインで何も見つけることができなかったので、途方に暮れています...

誰が何が起こっているのか知っていますか?

ありがとう。

編集

それで、問題は見知らぬ人になりました。基本的に、私はライブラリから何かを行うすべてのコードをコメントアウトし、関数呼び出しを同じままにしました。これを実行し、ブレークポイントを使用してgdbで実行すると、関数呼び出しで出力されるすべてのメモリアドレスは正常であり、Python id()関数と一致し、アドレスのprintf()と一致します。

問題が何であるかを確認するために、コードのコメントを外し始めました。問題は宣言にあります:

double nrcs_h_d[MAX_NINC_S*MAX_SCAT_S];
double nrcs_v_d[MAX_NINC_S*MAX_SCAT_S];

両方の行をコメントアウトすると、クラッシュは発生しません。2行目だけをコメントアウトすれば、クラッシュは発生しません。ただし、コメントアウトされた行がない場合はクラッシュします。

奇妙なことに、MAX_NINC_SとMAX_SCAT_Sはどちらも500に等しいのです。したがって、これらの配列のサイズはわずか数メガバイトです...コードの他の場所では、数百メガバイトの配列が適切に割り当てられています。

また、上記の行を次のように置き換えた場合:

double *nrcs_h_d, *nrcs_v_d;
nrcs_h_d = (double *)malloc(MAX_NINC_S*MAX_SCAT_S*sizeof(double));
nrcs_v_d = (double *)malloc(MAX_NINC_S*MAX_SCAT_S*sizeof(double));

正常に動作しているようです...したがって、問題はスタックに割り当てすぎていることに関連しているようです。

したがって、質問は次のようになります。

なぜgdbは、これがセグメンテーション違反が発生するコードの行であると表示せず、代わりに関数呼び出しであると表示するのですか?

その割り当てが行われると、コアダンプファイルのメモリアドレスがすべて台無しになっているように見えるのはなぜですか?

ありがとう。

4

2 に答える 2

0

スタック スペースは下向きに成長し、ヒープ スペースは上向きに成長することを思い出してください。仮想メモリ空​​間の上部に近いアドレス (例: 0x7fff5fab51b0) はスタック割り当て変数であり、下部に近いアドレス (例: 0x46cb4ec) はヒープ割り当て変数です。通常、仮想メモリ空​​間は物理メモリよりもはるかに大きいことに注意してください。お使いのオペレーティング システムとアーキテクチャは、最大 128 GiB の仮想メモリをサポートしているようです。

Python は動的メモリ割り当てに大きく依存しているため、オブジェクトをヒープに配置することになります。これがid()、低い側でアドレスを返す傾向がある理由です。C コードがスタックに割り当てられた変数に値をコピーし、その後それらのローカル コピーを使用して関数を呼び出そうとすると、上位側のアドレスが再び表示されます。

行番号が提供されています: src/seam_processor.c:47. そこに何か面白いものはありますか?GDB が不平を言っているさまざまなメモリ アドレスは、 stack 上のさまざまなメモリ アドレスであり、それらはすべて連続しており、ほとんどすべてがポインタのように見えます (それらはすべて 8 バイト幅であるため)。

(これは手元にある情報で私ができる最良の回答です。改訂を提案したり、追加情報を提供したりしてください。)

于 2012-08-15T20:07:41.863 に答える
0

1 つの考えられる説明は、関数内のローカル変数のデータの割り当てが、特定の関数内のコードが実行される前に発生することです。

コンパイラは、必要なスタック領域の量を計算し、関数内のステートメントに到達する前に割り当てます。したがって、関数の実際の実行は次のようになります。

  1. すべてのローカル関数変数にストレージの量を割り当てます。
  2. 関数内のステートメントの実行を開始する

そうすれば、関数 1 から別の関数 2 を呼び出すときに、関数 1 のローカル変数が関数 2 のローカル変数からのデータに影響されることはありません。

したがって、あなたの場合、ローカルデータ変数に必要なスペースはスタックが利用できるよりも多く、関数コードの実行が開始される前の時点で例外が発生します。

于 2013-07-25T09:51:16.640 に答える