Runtime: Исключение через PInvoke

Созданный на 26 июл. 2017  ·  3Комментарии  ·  Источник: dotnet/runtime

Я тестирую следующий код.

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$ 

вот основной файл 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

Является ли это нормальным поведением, когда блок перехвата в основной функции не перехватывает исключение?

Самый полезный комментарий

Одна из причин заключается в том, что мы на самом деле не знаем, как распространять исключение через собственный код, вызывающий управляемый обратный вызов, поскольку мы понятия не имеем, что это был за код. Это мог быть код C, код C++, код ASM или код любого другого языка. Если бы мы просто пропустили эти кадры, и это был бы, например, C++, мы бы не вызывали деструкторы объектов стека, что могло бы привести к утечке памяти или отказу от заблокированных блокировок и т. д. Если бы мы попытались сгенерировать какое-то предопределенное исключение C++ через это, собственный код мог бы его проглотить. непреднамеренно. Или даже может сломать некоторые среды выполнения, не готовые к обработке исключений.

Все 3 Комментарий

Пересечение исключений, управляемое собственной границей (например, в вашем случае, когда обратный вызов вызывается из собственного кода и вызывает исключение), намеренно не поддерживается в ядре dotnet. Вам нужно будет перехватывать все исключения в ваших обратных вызовах, которые вы вызываете из собственного кода.

Одна из причин заключается в том, что мы на самом деле не знаем, как распространять исключение через собственный код, вызывающий управляемый обратный вызов, поскольку мы понятия не имеем, что это был за код. Это мог быть код C, код C++, код ASM или код любого другого языка. Если бы мы просто пропустили эти кадры, и это был бы, например, C++, мы бы не вызывали деструкторы объектов стека, что могло бы привести к утечке памяти или отказу от заблокированных блокировок и т. д. Если бы мы попытались сгенерировать какое-то предопределенное исключение C++ через это, собственный код мог бы его проглотить. непреднамеренно. Или даже может сломать некоторые среды выполнения, не готовые к обработке исключений.

Большое Вам спасибо.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги