我正在测试以下代码。
using System;
using System.Runtime.InteropServices;
class Program
{
[DllImport("libupcall.so")]
public static extern void register_callback(Callback cb);
[DllImport("libupcall.so")]
public static extern void upcall();
public static void MyStaticCallback(int val)
{
throw new Exception("error");
}
public delegate void Callback(int var);
static Callback cbMyStaticCallback = MyStaticCallback;
static void Main(string[] args)
{
try {
register_callback(MyStaticCallback);
upcall();
} catch (Exception e) {
Console.WriteLine("Catch clause caught : {0} \n", e.Message);
}
}
}
libupcall.so 基于以下 C 源代码
#include <stdio.h>
typedef void (*callback)(int val);
callback gCB;
extern void register_callback(callback cb)
{
printf("register_callback:%p ----\n", (void *)cb);
gCB = cb;
}
extern void upcall()
{
static int c = 0;
printf("upcall ----\n");
gCB(c++);
}
dotnet run 以未处理的异常退出,如下所示。
twoflower@js2-desktop:~/dev/complexexception$ sudo dotnet run
register_callback:0x7f3a041f407c ----
upcall ----
Unhandled Exception: System.Exception: error
at Program.MyStaticCallback(Int32 val) in /home/twoflower/dev/complexexception/Program.cs:line 14
at Program.upcall()
at Program.Main(String[] args) in /home/twoflower/dev/complexexception/Program.cs:line 24
twoflower@js2-desktop:~/dev/complexexception$
这是corefile bt。
* thread dotnet/coreclr#1: tid = 0, 0x00007fda93b26428 libc.so.6`__GI_raise(sig=6) + 56 at raise.c:54, name = 'dotnet', stop reason = signal SIGABRT
* frame #0: 0x00007fda93b26428 libc.so.6`__GI_raise(sig=6) + 56 at raise.c:54
frame dotnet/coreclr#1: 0x00007fda93b2802a libc.so.6`__GI_abort + 362 at abort.c:89
frame dotnet/coreclr#2: 0x00007fda9326258c libcoreclr.so`??? + 124
frame dotnet/coreclr#3: 0x00007fda9326148b libcoreclr.so`??? + 235
frame dotnet/coreclr#4: 0x00007fda92f0b893 libcoreclr.so`??? + 531
frame dotnet/coreclr#5: 0x00007fda92f0cd71 libcoreclr.so`??? + 593
frame dotnet/coreclr#6: 0x00007fda92fcaae3 libcoreclr.so`??? + 51
frame dotnet/coreclr#7: 0x00007fda93ecb263 libgcc_s.so.1`_Unwind_RaiseException(exc=0x0000000002467530) + 115 at unwind.inc:113
frame dotnet/coreclr#8: 0x00007fda9446790c libstdc++.so.6`__cxa_throw + 92
frame dotnet/coreclr#9: 0x00007fda9322749d libcoreclr.so`??? + 77
frame dotnet/coreclr#10: 0x00007fda92fd781e libcoreclr.so`??? + 273
frame dotnet/coreclr#11: 0x00007fda88e4b7b2 libupcall.so`upcall + 45 at upcall.c:16
frame dotnet/coreclr#12: 0x00007fda19d85ae6
frame dotnet/coreclr#13: 0x00007fda19d8588e
frame dotnet/coreclr#14: 0x00007fda92fd67b7 libcoreclr.so`??? + 124
frame dotnet/coreclr#15: 0x00007fda92eec630 libcoreclr.so`??? + 1264
这是在 Main 函数上捕获块而不捕获异常的正常行为吗?
dotnet core 有意不支持跨管理到本机边界的异常(例如在您的情况下,从本机代码调用回调并引发异常)。 您需要在从本机代码调用的回调中捕获所有异常。
原因之一是我们真的不知道如何通过调用托管回调的本机代码传播异常,因为我们不知道它是什么类型的代码。 它可能是 C 代码、C++ 代码、ASM 代码或实际上任何其他语言代码。 如果我们只是跳过那些帧,例如 C++,我们将不会调用堆栈对象的析构函数,因此可能会泄漏内存或放弃锁定的锁等。如果我们试图通过它抛出一些预定义的 C++ 异常,本机代码可能会吞下它无意中。 或者它甚至可以破坏一些尚未准备好处理异常的运行时。
非常感谢你。
最有用的评论
原因之一是我们真的不知道如何通过调用托管回调的本机代码传播异常,因为我们不知道它是什么类型的代码。 它可能是 C 代码、C++ 代码、ASM 代码或实际上任何其他语言代码。 如果我们只是跳过那些帧,例如 C++,我们将不会调用堆栈对象的析构函数,因此可能会泄漏内存或放弃锁定的锁等。如果我们试图通过它抛出一些预定义的 C++ 异常,本机代码可能会吞下它无意中。 或者它甚至可以破坏一些尚未准备好处理异常的运行时。