longjmp und Net
-
Hallo zusammen,
Ich beschäftigte mich gerade ein wenig mit C++/CLI. Ich möchte eine C Bibliothek wrappen, um diese in .Net Sprachen nutzen zu können. Diese C Bibliothek benutzt intern
longjmp
für das Exception-Handling. Dabei spürt man von aussen davon meistens nichts, ausser man verwendet Callbacks. In diesen Callback verwende ich .Net Code und diese Bibliotheksfunktionen, welche einenlongjmp
auslösen können.
Das sieht also in etwa irgendwie so aus:void* callback(void* userdata) { Stream stream = (Stream)GCHandle.FromIntPtr((IntPtr)userdata).Target; // mit stream arbeiten. lib_function(); // <- Bibliotheksfunktion verwenden, welche einen longjmp auslösen könnte. // weiter mit stream arbeiten. // usw. } // Und irgendwo halt: GCHandle handle = GCHandle.Alloc(stream); secure_lib_function(&callback, (void*)GCHandle.ToIntPtr(handle)); handle.Free();
Die Funktion
secure_lib_function
fängt allelongjmp
ab. Kann man das problemlos so verwenden oder muss man da auf etwas achten? Mir istlongjmp
nicht so ganz geheuer, schliesslich habe ich es grundsätzlich noch nie eingesetzt. Ich weiss also kaum, was da im C Code passiert. Daher habe ich mühe abzuschätzen, wie sich dies auf das C++ und .Net Codegemisch auswirktGrüssli
-
Eher "CLI/C++" ".Net" gemisch! Schon "C++" zu "CLI/C++" ist ein schwerer Unterschied! Dieser liegt am Compiler!
-
Ich kenne mich auch zu wenig damit aus, aber soweit ich es beurteilen kann, darfst du
setjmp
einfach niemals innerhalb einestry-catch
-Blocks verwenden, da es sich um einen speziellen tail call (also einen Call, bei dem nie an die ursprüngliche Adresse zurückgesprungen wird) handelt, der eine effektive Vorhersage des control flows verunmöglicht. Darum gehen dann Aspekte wie RAII flöten.Du hast nun die Funktion
secure_lib_function
, welche deinlongjmp
irgendwie abkapselt und besagt, dass du wieder sicher beim nächsten Statement (handle.Free();
) landest, oder? In diesem Fall sehe ich kein Problem, da sich der C-Code um das korrekte Verhalten kümmern muss. Undefiniert wird das Verhalten erst dann, wenn du aus dem CLI-Kontext mitlongjmp
rausspringst und niemals zurückkehrst. Allerdings wird dies wohl einfach einen schweren Fehler auslösen.MfG
-
/rant/ schrieb:
Du hast nun die Funktion
secure_lib_function
, welche deinlongjmp
irgendwie abkapselt und besagt, dass du wieder sicher beim nächsten Statement (handle.Free();
) landest, oder?Genau. Zumindest sagt das die Dokumentation der Bibliothek. Ich hoffe, dass es auch stimmt
/rant/ schrieb:
Undefiniert wird das Verhalten erst dann, wenn du aus dem CLI-Kontext mit
longjmp
rausspringst und niemals zurückkehrst.Was genau meinst du damit?
Im übrigen, würde ich gerne meine Fragestellung noch etwas erweitern, weil ich gerade bemerkt habe, dass es da noch zusätzliche Probleme geben könnte. Wenn
secure_lib_function
alles abfängt, könnte das zum Problem werden, wenn in der Callback-Funktion eine Net-Exception geworfen wird? Exception-Handling wird, wenn ich mich recht erinnere, doch über diese Jump-Techniken implementiert. Sollte ich daher sicherheitshalber alle Net-Exceptions abfangen und anders durchleiten? Wäre theoretisch und nur mit relativ geringem Aufwand möglich.
Oder spielt das bei einer Net-Exception keine Rolle, weil das dann irgendwie durch die CLR erledigt wird und das C Exception Handling der Bibliothek nicht beeinflusst?Grüssli
-
Deine
secure_lib_function
wird mit einer .NET Exception nicht klar kommen. Ich würde sogar soweit gehen und behaupten, dass dies recht bös enden kann für dich. Als Faustregel gilt: niemals strukturierte und unstrukturierte Fehlerbehandlung miteinander vermischen! Du kannst niemals wissen, wie die Exceptions bei einem Compiler, oder besser gesagt bei unterschiedlichen Compiler Versionen implementiert sind. Oder beim .NET Framework. Oder der verwendeten C-Runtime. Oder wie die Kombination von all dem reagiert.Zu deiner Frage: ein tail call wie
longjmp
ist technisch gesehen mit einem Jump aus der aktuellen Funktion heraus vergleichbar. Es ist nicht wie bei einem normalen Call ein Rücksprung vorgesehen. Darum ist es möglich, dass der tail call dein Programm beendet, ohne dass du den Call Stack zurück nach oben gehst und am Ende wieder bei der Main landest, wo du dann mittelsreturn
dein Programm beendest. Dadurch werden praktisch alle höheren Prinzipien der strukturierten Programmierung verunmöglicht. Exception-Handling, RAII, aber auch manuellDispose
-Aufrufe und alles andere fallen plötzlich weg.Ich würde darum sagen, dass du die
secure_lib_function
so benutzt, dass dein Callback bestimmt keine .NET Exception wirft. Dann bist du nähmlich der Dokumentation nach auf der sicheren Seite und ladest, falls mal einlongjmp
kommt, dennoch wieder in deinem eigenen Programm.MfG
-
Danke /rant/.
Planung kann jetzt weitergehen. Gibt noch einiges zu klären und festzuhalten. Mal schauen, ob ich die Tage nochmals im C++/CLI Forum vorbeischauen werdeGrüssli
-
/rant/ schrieb:
Zu deiner Frage: ein tail call wie
longjmp
(...)
longjmp ist doch kein tail call.
-
hustbaer schrieb:
/rant/ schrieb:
Zu deiner Frage: ein tail call wie
longjmp
(...)
longjmp ist doch kein tail call.Okay, okay... ist ja gut. Der Begriff ist in der Tat vielleicht nicht ganz korrekt hier
Ich habe anfänglich auch von einem speziellen tail call gesprochen, weil wie bei einem tail call das aktuelle Stack Frame gekillt bzw. bedeutungslos gemacht wird. Und im Unterschied zum verwalteten tail call kann hier einiges an Informationen verloren gehen. Zumindest ist es möglich. Und darum kann man es getrost so behandeln
Oder nicht?