0

既存の C++ 共有ライブラリの周囲に Mono/.Net ラッパー クラスを作成しようとしていますが、アンマネージ コードの実行中に問題が発生しています。ライブラリを正常に呼び出していますが、アンマネージ コードがセグメンテーション エラーをスローしています。これは、C++ で記述されたアンマネージ アプリケーションからライブラリ関数を呼び出した場合には発生しません。

C++ ヘッダー コード:

extern "C" void some_function();

C++ ソース コード:

void some_function()
{
    std::vector<uint8_t> v = std::vector<uint8_t> { 0x00 };
}

C# P/Invoke コード:

[DllImport("somelib.so", EntryPoint = "some_function")]
public static extern void some_function();

ご覧のとおり、マーシャリングが必要なパラメーターがないため、渡されるデータに問題はありません。このライブラリのいくつかの関数でこの問題が発生していますが、問題なくいくつかを呼び出すこともできます. 通常、segfault はメモリを割り当てようとしたときに発生しますが (少なくとも 1 つの場合は std::vector の場合)、常にではありません。gdb でデバッグしようとしましたが、C# から呼び出した場合は 5 つのスレッドがあり、C++ から呼び出した場合は 1 つしかないことに気付きました。それが大きな違いを生む場合、私はUbuntuのMonoでもこれを行っています。

P/Invoke 呼び出しを実装しているときに見逃した可能性のあるものはありますか、それともここで何か他のことが起こっていますか?

更新: 最初と同じ問題を抱えている 2 番目のより単純な関数の例を追加しました。

更新: 最初の例を削除し、問題のシンプルかつ完全な実装を提供しました。以前のテストでは、ベクトルを値で初期化していませんでした。ベクトルを初期化する方法をいくつか試しましたが、うまくいきません。初期化中を含め、ベクター内の新しいアイテムにメモリが割り当てられるたびに、セグメンテーション違反が発生するようです。

4

2 に答える 2

3

私の知る限り、Unix プラットフォームでの Mono のデフォルトの呼び出し規約はcdecl. おそらくあなたのC++コードと一致します。だから、それは問題ではないと思います。ただし、再確認する価値があります。おそらく、pinvoke で呼び出し規約を明示的に指定してください。

UnmanagedType.Struct戻り値に使用している理由がわかりません。私が知る限り、それは正しくありません。.net では、構造体が としてマーシャリングされますが、VARIANTこれは絶対に必要なものではありません。Linux の Mono pinvoke に何らかの意味があるかどうかUnmanagedType.Structはわかりませんが、いずれにせよ存在しないはずなので、削除する必要があります。

また、エントリ ポイントに名前を付ける必要もありません。したがって、p/invoke を単純化します。

[DllImport("somelib.so")]
public static extern some_struct some_function();

もう 1 つの明らかな潜在的な不一致は、ネイティブ構造体定義とマネージド構造体定義の間です。あなたが言った:

ご覧のとおり、マーシャリングが必要なパラメーターはないため、渡されるデータに問題はありません。

それは本当ですが、渡される戻り値はどうでしょうか。これもマーシャリングが必要であり、適切に処理する必要があります。構造体型 (ネイティブとマネージの両方) の定義を確認できなければ、判断する立場にはありません。ここでそれらを表示できない場合は、それらが一致していることを確認する必要があります。

最後に、コンパイラと pinvoke マーシャラーが構造体の戻り値に対して異なる ABI を想定している可能性があります。それは常に灰色の領域です。戻り値として単純な型を常にお勧めし、構造体を出力パラメーターとして返します。

私が賭けなければならなかったとしたら、問題は構造体の定義にあると言えますが、残念ながらあなたはそれを示していません。


アップデート

void質問の編集は、戻り値の型を持つ関数に問題があることを示しています。この場合、問題はネイティブ コードにあり、p/invoke にはないというのが唯一の正しい結論です。これをさらに追跡するには、ネイティブ コードを確認する必要があります。

于 2013-09-18T06:42:03.180 に答える
1

最近、この正確な問題に遭遇しました。マネージ実行可能ファイルからアンマネージ DLL 内の関数を呼び出すと、割り当てができなかっstd::vectorたり、クラッシュせずにアクセス違反が発生したりしました。std::map同様に、管理されていない実行可能ファイルから直接呼び出すと、すべてが機能しました。

私たちの場合、マネージ コンテキストから呼び出されたときに間違った (そして壊れている可能性がある) std DLL が実行時に読み込まれていたことが問題であることが判明し、この DLL の場所を PATH から削除するだけで問題が修正されました。

最初はエラー メッセージに原因のヒントが示されなかったため、これを特定するのは困難でしたが、標準ライブラリを (デフォルトの静的リンクではなく) 動的にリンクした後、アクセス違反によって問題の std DLL が特定され、次のことが発見されました。 PATH の間違ったバイナリ。

于 2017-06-17T19:01:05.103 に答える