Runtime: Exception via PInvoke

Créé le 26 juil. 2017  ·  3Commentaires  ·  Source: dotnet/runtime

Je teste le code suivant.

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 est basé sur le code source C suivant

#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 se termine avec une exception non gérée comme suit.

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$ 

voici le 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

Est-ce un comportement normal qui attrape le bloc sur la fonction principale et n'attrape pas l'exception ?

Commentaire le plus utile

L'une des raisons est que nous ne savons pas vraiment comment propager l'exception via le code natif qui a appelé le rappel géré, car nous n'avons aucune idée de quel type de code il s'agissait. Cela aurait pu être du code C, du code C++, du code ASM ou en fait n'importe quel autre code de langage. Si nous ignorions simplement ces cadres et qu'il s'agissait par exemple de C++, nous n'appellerions pas de destructeurs d'objets de pile, ce qui pourrait entraîner une fuite de mémoire ou l'abandon de verrous verrouillés, etc. Si nous tentons de lancer une exception C++ prédéfinie, le code natif pourrait l'avaler involontairement. Ou cela peut même casser certains runtimes qui ne sont pas prêts à traiter les exceptions.

Tous les 3 commentaires

Le franchissement d'exception géré vers la frontière native (comme dans votre cas lorsqu'un rappel est appelé à partir du code natif et qu'il lève une exception) n'est intentionnellement pas pris en charge sur le noyau dotnet. Vous devrez intercepter toutes les exceptions dans vos rappels que vous appelez à partir du code natif.

L'une des raisons est que nous ne savons pas vraiment comment propager l'exception via le code natif qui a appelé le rappel géré, car nous n'avons aucune idée de quel type de code il s'agissait. Cela aurait pu être du code C, du code C++, du code ASM ou en fait n'importe quel autre code de langage. Si nous ignorions simplement ces cadres et qu'il s'agissait par exemple de C++, nous n'appellerions pas de destructeurs d'objets de pile, ce qui pourrait entraîner une fuite de mémoire ou l'abandon de verrous verrouillés, etc. Si nous tentons de lancer une exception C++ prédéfinie, le code natif pourrait l'avaler involontairement. Ou cela peut même casser certains runtimes qui ne sont pas prêts à traiter les exceptions.

Merci beaucoup.

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

aggieben picture aggieben  ·  3Commentaires

matty-hall picture matty-hall  ·  3Commentaires

jamesqo picture jamesqo  ·  3Commentaires

GitAntoinee picture GitAntoinee  ·  3Commentaires

jzabroski picture jzabroski  ·  3Commentaires