4

Linux x86_64 でコンパイルするために使用している C# ライブラリのネイティブ依存関係を取得しようとしています。コード自体はプラットフォームに依存せず、簡単にコンパイルできます。

ただし、最初にコンパイル済みの依存関係を使用して Linux でプロジェクトを実行しようとした後、後でライブラリと segfault から奇妙な結果が得られ始めました。調査の結果、P/Invoke 関数のパラメーターが正しい順序で渡されていないようです。それらが逆方向に渡されているようです。

いくつかの異なる方法でネイティブ依存関係をコンパイルし、異なる呼び出し規約を明示的に定義しようとしました。何も機能していないようです。

C# extern メソッド定義

[DllImport(InteropUtil.PLATFORM_DLL)]
public static extern NavStatus dtqFindPath(IntPtr query
    , NavmeshPoint startPosition
    , NavmeshPoint endPosition
    , IntPtr filter
    , [In, Out] uint[] resultPath
    , ref int pathCount
    , int maxPath);

関連する C++ 定義

#if _MSC_VER    // TRUE for Microsoft compiler.
#define EXPORT_API __declspec(dllexport) // Required for VC++
#else
#define EXPORT_API // Otherwise don't define.
#endif

extern "C"
{

    EXPORT_API dtStatus dtqFindPath(dtNavMeshQuery* query 
        , rcnNavmeshPoint startPos
        , rcnNavmeshPoint endPos
        , const dtQueryFilter* filter
        , dtPolyRef* path
        , int* pathCount
        , const int maxPath)
    {
        return query->findPath(startPos.polyRef
            , endPos.polyRef
            , &startPos.point[0]
            , &endPos.point[0]
            , filter
            , path
            , pathCount
            , maxPath);
    }
}

g++ コンパイラの設定

g++ -shared -o cai-nav-rcn.so.1 -g -fPIC -I Detour/Include -I DetourCrowd/Include -I Nav/Include Detour/Source/*.cpp DetourCrowd/Source/*.cpp Nav/Source/*.cpp

以下の出力では、dtqFindPath行は順不同のパラメーターを明確に示しています。maxPath100 ( 0x64) である必要がありますが、1298 です。1298 は構造体の最初intですstartPos。代わりに 100 が の値ですpath

部分的な GDB 出力

Thread 1 (Thread 0x7fef64330740 (LWP 3923)):
#0  0x00007fef63823ce9 in waitpid () from /usr/lib/libpthread.so.0
#1  0x00000000004ae448 in ?? ()
#2  0x0000000000503b8b in ?? ()
#3  0x00000000004226b2 in ?? ()
#4  <signal handler called>
#5  0x00007feef052339c in dtNavMeshQuery::findPath (this=0x5405610, startRef=88101520, endRef=4203419680, startPos=0x7fff5fd3975c, endPos=0x7fff5fd3974c, filter=0x7fef64176ec0, path=0x64, pathCount=0x44d6595341be38e0, maxPath=1298) at Detour/Source/DetourNavMeshQuery.cpp:958
#6  0x00007feef0534d19 in dtqFindPath (query=0x5405610, startPos=..., endPos=..., filter=0x7fef64176ec0, path=0x64, pathCount=0x44d6595341be38e0, maxPath=1298) at Nav/Source/DetourNavMeshQueryEx.cpp:234
#7  0x0000000041ec2140 in ?? ()
...
#17 0x0000000005405610 in ?? ()
#18 0x0000000000000000 in ?? ()

私はすでに両端のrcnNavmeshPointと構造体のサイズを比較しましたが、それらは同じです。NavmeshPointP/Invoke 呼び出しに入るパラメーターは適切な順序で、デバッガーでチェックされます。

私が使用しようとしているライブラリがCritterAIであることを含めることもできます。

私の質問は次のとおりです。これら 2 つのコード間の呼び出し規約を一致させるには、何を変更すればよいですか?


アップデート

問題を切り分けました。適切に渡されていないのは構造体です。これを実証するために SSCCE を作成しました。

相互運用.cpp

#include <cstdio>

#if _MSC_VER
#define EXPORT_API __declspec(dllexport)
#else
#define EXPORT_API 
#endif

struct s
{
    unsigned int a;
    float b[3];
};

extern "C"
{
    EXPORT_API void testStruct(s str)
    {
        printf("STRUCT NATIVE\n");
        printf("SIZE: %u\n", sizeof(s));
        printf("%u, (%f, %f, %f)\n", str.a, str.b[0], str.b[1], str.b[2]);
    }
}

cs.cs

using System;
using System.Runtime.InteropServices;

namespace InteropTest
{
    [StructLayout(LayoutKind.Sequential)]
    public struct v
    {
        public float X;
        public float Y;
        public float Z;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct s
    {
        public uint A;
        public v B;
    }

    public class Test
    {
        [DllImport("./test.so")]
        public static extern void testStruct(s str);

        unsafe static void Main(string[] args)
        {
            s mStr;
            mStr.A = 22;
            mStr.B.X = 33f;
            mStr.B.Y = 44f;
            mStr.B.Z = 55f;
            Console.WriteLine("STRUCT MANAGED");
            Console.WriteLine("SIZE: " + sizeof(s));
            Console.WriteLine(mStr.A + ", (" + mStr.B.X + ", " + mStr.B.Y + ", " + mStr.B.Z + ")");
            testStruct(mStr);
        }
    }
}

でコンパイル

g++ -shared -o test.so -g -fPIC interop.cpp && mcs /unsafe cs.cs && ./cs.exe

私のシステムの出力

STRUCT MANAGED
SIZE: 16
22, (33, 44, 55)
STRUCT NATIVE
SIZE: 16
22, (33.000000, 0.000000, 3.179688)

他のいくつかのテストでは、構造体が「スキップ」されていることが示されています。ここでは、印刷str.aによって次の非構造体パラメーターの値が出力されます。構造体の残りの部分はガベージのようです。

4

1 に答える 1