0

私は C++ の使用にかなり慣れていませんが、64 ビット XP プラットフォームで matlab 用のバージョン 2.0.2 のSBML ツールボックスをコンパイルしようとしています。SBML ツールボックスは、 Xerces 2.8 とlibsbml 2.3.5に依存しています。

ツールボックスを 32 ビット マシン上でビルドおよびコンパイルすることができました。テストすると動作します。しかし、64 ビット マシンで再構築した後 (これは非常に残念です!)、長い .xml ファイルを読み込もうとすると、セグメンテーション エラーが発生します。

この問題は、ポインター アドレスの問題が原因であると思われます。

セグメンテーション違反からのスタック トレースは次のように始まります。

[ 0] 000000003CB3856E libsbml.dll+165230 (StringBuffer_append+000030)
[ 6] 000000003CB1BFAF libsbml.dll+049071 (EventAssignment_createWith+001631)
[ 12] 000000003CB1C1D7 libsbml.dll+049623 (SBML_formulaToString+000039)
[ 18] 000000003CB2C154 libsbml.dll+115028 (

だから私は libsbml コードの StringBuffer_append 関数を見ています:

LIBSBML_EXTERN
void
StringBuffer_append (StringBuffer_t *sb, const char *s)
{
  unsigned long len = strlen(s);


  StringBuffer_ensureCapacity(sb, len);

  strncpy(sb->buffer + sb->length, s, len + 1);
  sb->length += len;
}

ensureCapacity は次のようになります。

LIBSBML_EXTERN
void
StringBuffer_ensureCapacity (StringBuffer_t *sb, unsigned long n)
{
  unsigned long wanted = sb->length + n;
  unsigned long c;


  if (wanted > sb->capacity)
  {
    /**
     * Double the total new capacity (c) until it is greater-than wanted.
     * Grow StringBuffer by this amount minus the current capacity.
     */
    for (c = 2 * sb->capacity; c < wanted; c *= 2) ;
    StringBuffer_grow(sb, c - sb->capacity);
  }                   
}

StringBuffer_grow は次のようになります。

LIBSBML_EXTERN
void
StringBuffer_grow (StringBuffer_t *sb, unsigned long n)
{
  sb->capacity += n;
  sb->buffer    = (char *) safe_realloc(sb->buffer, sb->capacity + 1);
}

それは可能性が高いですか?

strncpy(sb->buffer + sb->length, s, len + 1);

StringBuffer_append は私のセグメンテーション違反の原因ですか?

もしそうなら、誰かが修正を提案できますか?私は本当に C++ を知りません。ポインタとメモリのアドレス指定に特に戸惑っています。そのため、あなたが何について話しているのかわからない可能性があります。手を握る必要があります。

また、他の誰かが Microsoft Visual C++ Express Edition を使用して 64 ビット システム用に C++ をコンパイルしようとしている場合に備えて、ビルド プロセスの詳細をここにオンラインで公開します。

前もって感謝します!

-ベン

4

8 に答える 8

1

印刷するか、デバッガーを使用して、いくつかの中間変数に対して取得する値を確認してください。StringBuffer_append()O / P lenで、StringBuffer_ensureCapacity()で、ループの前とループ内でsb->capacityとcを観察します。値が意味をなすかどうかを確認します。

文字列の終わりを超えてデータにアクセスすると、セグメンテーション違反が発生する可能性があります。

64ビットO/Sではなく32ビットマシンで動作したという奇妙な事実も手がかりです。物理メモリとページファイルのメモリサイズは2台のマシンで同じですか?また、64ビットマシンでは、カーネルスペースが32ビットマシンよりも大きく、32ビットO/Sのメモリスペースのユーザー部分にあった使用可能なメモリスペースを消費する場合があります。XMLの場合、ドキュメント全体がメモリに収まる必要があります。これが問題になる場合は、サイズを設定するためのスイッチがいくつかある可能性があります。問題の原因となるマシンの違いは、非常に大きなストリングを使用している場合にのみ当てはまります。文字列が大きくない場合は、64ビット環境ではうまく機能しないライブラリまたはユーティリティメソッドに問題がある可能性があります。

また、他に試すことがない場合は、単純/小さなxmlファイルを使用して開始します。

sb->lengthをどこで初期化しますか。あなたの問題はstrncpy()にある可能性がありますが、32ビット->64ビットのO/Sの変更が重要である理由はわかりません。最善の策は、中間値を調べることです。そうすれば、問題が明らかになります。

于 2009-02-25T16:22:19.843 に答える
1

libsbml の開発者の 1 人である私は、これにつまずきました。これはまだあなたにとって問題ですか?それまでの間、libsbml 5 をリリースしました。64 ビット バージョンと 32 ビット バージョンを分け、テストを大幅に改善しました。以下をご覧ください。

http://sf.net/projects/sbml/files/libsbml

于 2011-06-25T16:53:07.097 に答える
0

質問に対する bk1e のコメントに応えて - 残念ながら、新しいバージョン 3 では動作しない COBRA ツールボックスで使用するにはバージョン 2.0.2 が必要です。

また、デバッグしようとしていくつかの壁にぶつかっています-私は.dllを構築しているので、xercesを再コンパイルしてMSVC ++で同じデバッグ設定があることを確認することに加えて、デバッグを行うためにMatlabプロセスにアタッチする必要もあります- この環境での限られた経験からすると、これはかなり大きな飛躍であり、まだ深く掘り下げていません。

バッファーの割り当てまたは展開に明らかな構文の問題があることを期待していました。でも、あと数日は痛みが続くようです。

于 2009-02-26T18:25:56.027 に答える
0

StringBuffer は次のように定義されます。

/**
 * Creates a new StringBuffer and returns a pointer to it.
 */
LIBSBML_EXTERN
StringBuffer_t *
StringBuffer_create (unsigned long capacity)
{
  StringBuffer_t *sb;


  sb           = (StringBuffer_t *) safe_malloc(sizeof(StringBuffer_t));
  sb->buffer   = (char *)           safe_malloc(capacity + 1);
  sb->capacity = capacity;

  StringBuffer_reset(sb);

  return sb;
}

スタック トレースの詳細は次のとおりです。

[  0] 000000003CB3856E              libsbml.dll+165230 (StringBuffer_append+000030)
[  6] 000000003CB1BFAF              libsbml.dll+049071 (EventAssignment_createWith+001631)
[ 12] 000000003CB1C1D7              libsbml.dll+049623 (SBML_formulaToString+000039)
[ 18] 000000003CB2C154              libsbml.dll+115028 (Rule::setFormulaFromMath+000036)
[ 20] 0000000001751913              libmx.dll+137491 (mxCheckMN_700+000723)
[ 25] 000000003CB1E7B2              libsbml.dll+059314 (KineticLaw_getFormula+000018)
[ 37] 0000000035727749              TranslateSBML.mexw64+030537 (mexFunction+009353)
于 2009-02-25T18:06:29.250 に答える
0

unsigned longWindows の 64 ビット マシンでサイズに使用する安全な型ではありません。Linux とは異なり、Windows はlong32 ビット アーキテクチャと 64 ビット アーキテクチャの両方で 32 ビットと定義しています。したがって、追加されるバッファーのサイズが 4 GB を超えた場合 (または、長さが 4 GB を超える文字列を追加しようとしている場合)、unsigned long型宣言をsize_t(64 ビット アーキテクチャでは 64 ビットである) に変更する必要があります。すべてのオペレーティング システムで)。

ただし、1.5 MB のファイルしか読み取っていない場合、StringBuffer のサイズが 4 GB を超える方法がわからないため、これは袋小路かもしれません。

于 2011-03-10T19:24:03.397 に答える
0

それが StringBuffer_* 関数のいずれかにあった場合、それはスタック トレースにあるようです。_ensureCapacity と _grow の実装方法に同意しません。realloc が機能するかどうかをチェックする関数はありません。Realloc の失敗は、確実にセグメンテーション違反を引き起こします。_ensureCapacity の後に null のチェックを挿入します。_ensureCapacity と _grow のやり方では、off-by-one エラーが発生する可能性があるようです。Windows で実行している場合、64 ビット システムと 32 ビット システムではページ保護メカニズムが異なるため、失敗する可能性があります。(ページ保護が弱いシステムでは、malloc されたメモリで off-by-one エラーが発生することがよくあります。)

于 2009-02-26T03:48:52.733 に答える
0

safe_malloc と safe_realloc が、要求されたメモリを取得できない場合にプログラムを中止するなど、賢明なことを行うと仮定しましょう。そうすれば、プログラムは無効なポインターで実行を継続しません。

次に、必要な容量と比較して、StringBuffer_ensureCapacity がバッファをどの程度大きくするかを見てみましょう。オフバイワンエラーではありません。これは、2 分の 1 の誤差です。

あなたのプログラムが x32 でどのように動作したかはわかりません。

于 2009-02-26T04:26:19.523 に答える
0

問題はほとんど何でもありえます。確かに、strncpy が何か悪いことをしている可能性はありますが、ほとんどの場合、単純に不適切なポインターが渡されますこれはどこからでも発生する可能性があります。segfault (または Windows のアクセス違反) は、アプリケーションがアクセス許可のないアドレスに対して読み取りまたは書き込みを試みたことを意味します。本当の問題は、そのアドレスがどこから来たのかということです。ポインターをたどろうとした関数はおそらく問題ありません。しかし、別の場所から不正なポインタが渡されました。おそらく。

残念ながら、C コードのデバッグはいつでも簡単ではありません。コードが自分のものでない場合、それは簡単にはなりません。:)

于 2009-02-25T16:07:42.467 に答える