IndexOutOfRangeException - 无法使用 PInvoke 查看调用堆栈

Posted

技术标签:

【中文标题】IndexOutOfRangeException - 无法使用 PInvoke 查看调用堆栈【英文标题】:IndexOutOfRangeException - Cannot see call stack using PInvoke 【发布时间】:2015-03-10 13:27:16 【问题描述】:

我正在开发一个从 SerialPort 获取数据的 C# 应用程序,然后它使用 C++ 项目(我无法更改)来计算读取的数据。

C++ 项目正在使用一些本机 C 代码,这些代码将在计算数据时调用 C# 函数。

这是一些使用 PInvoke 调用 C++ 函数的被调用 C# 代码示例:

    [DllImport("MyLib.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
    public static extern void PacketHandler_HandlePacket(IntPtr packetHandler, IntPtr packet, int packetType);

    [SuppressUnmanagedCodeSecurity]
    [DllImport("MyLib.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    private static extern float DeviceManager_AddSampleToBattery(IntPtr self, float sample, double sampleRate);

    [SuppressUnmanagedCodeSecurity]
    [DllImport("MyLib.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    private static extern double DeviceManager_GetTimestamp(IntPtr self, int packetType);

    [DllImport("MyLib.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    private static extern void PacketHandler_AddCallbackBattery(IntPtr self, Delegate @delegate);

然后,C++ 代码:

extern "C"

    __declspec(dllexport) void _cdecl PacketHandler_HandlePacket(int * packetHandler, char * packet, int packetType)
        PacketHandler_handlePacket((PacketHandlerStruct *)packetHandler, packet, (PacketHandlerPacketType)packetType);

这个 C 函数正在调用我这样设置的 C# 函数:

__declspec(dllexport) void _cdecl  PacketHandler_AddCallbackBattery(int * packetHandler, void(*f)(void * obj, unsigned short int sample))
    PacketHandlerStruct * myPointer = ((PacketHandlerStruct *)packetHandler);
    myPointer->delegate.addSampleToBattery = f;

最后,C 代码将调用“addSampleToBattery”函数,这是这个 C# 回调(前两个是 PInvoke 调用,就像我发布的第一个一样)

private static float CallbackBattery(IntPtr self, ushort sample)
    
        var value = DeviceManager_AddSampleToBattery(DeviceManager, sample, Const.BaseBvpSampleRate);
        var timestamp = DeviceManager_GetTimestamp(DeviceManager, (int)PacketHandlerPacketType.Battery);
        SocketManager.OnNewBatteryArrived(value, timestamp);
        return value;
    

其他细节:

C# 委托声明如下:

 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 private delegate float DelegateBattery(IntPtr self, short sample);

 private static readonly DelegateBattery DelegateCallbackBattery = CallbackBattery;

设置如下:

var intptrDelegate = Marshal.GetFunctionPointerForDelegate(DelegateCallbackBattery);
var a = Marshal.GetDelegateForFunctionPointer(intptrDelegate, typeof(DelegateBattery));
PacketHandler_AddCallbackBattery(packetHandler, a);

所以,一切似乎都正常,但很多时候会发生 IndexOutOfRangeException。主要问题是,即使在加载了所有符号的调试模式下,我也看不到引发异常的行,因为只有反汇编视图可用,当然我无法从中获得有意义的信息。

Unhandled Exception: 'MyProgram.exe' (Win32): 
The program '[3000] MyProgram.exe' has exited with code 0 (0x0).
 System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.Threading.ThreadPoolWorkQueue.Dequeue(ThreadPoolWorkQueueThreadLocals tl, IThreadPoolWorkItem& callback, Boolean& missedSteal)
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

谢谢!

【问题讨论】:

调用@HansPassant 感谢@JonathonReinhart ;) 这里没有足够的信息。 不幸的是,我不知道提供哪些信息可以让其他用户更好地了解问题。相同的 C 代码在另一个应用程序中运行,所以问题不存在,它似乎随机抛出异常,所以不是在同一函数中的给定时间段之后。我怎样才能帮助您更好地理解这个问题?谢谢 您提供的代码非常少。显然有回调。我们看不到它。你可以做的是制作一个 MCVE。如果你不能这样做,那么你可以显示来自接口的功能 C 或 C++ 使用者的所有相关代码,以及匹配的 C# 代码。 【参考方案1】:

IndexOutOfRangeException 对应的语义表明您尝试访问的内存距离基内存地址太远,因此您不应该尝试推迟内存中的那个点。 p>

想象一个包含 3 个元素的 int 数组。如果您尝试索引 [3],即 *(base_address + (sizeof(int) * 3))* 被取消引用,以便为该值提供内存中该位置的下 4 个字节作为 int。唯一有效的索引是 0、1 和 2,因为这些偏移量在我们为其分配空间的 3 个元素的范围内。

我们仍然需要更多代码,因为我看不出这与异常消息有什么关系。

【讨论】:

以上是关于IndexOutOfRangeException - 无法使用 PInvoke 查看调用堆栈的主要内容,如果未能解决你的问题,请参考以下文章

什么是 IndexOutOfRangeException / ArgumentOutOfRangeException,我该如何解决?

什么是 IndexOutOfRangeException / ArgumentOutOfRangeException,我该如何解决?

什么是 IndexOutOfRangeException / ArgumentOutOfRangeException,我该如何解决?

什么是 IndexOutOfRangeException / ArgumentOutOfRangeException,我该如何解决?

什么是 IndexOutOfRangeException / ArgumentOutOfRangeException,我该如何解决?

IndexOutOfRangeException (C#) 与 ArrayIndexOutOfBoundsException(Java)