AccessViolationException in Interopfunktion



  • Salüü

    Ich bin gerade dabei einen Wrapper für FFmpeg zu schreiben (ich weiss, dass es das schon gibt, es geht mir in erster Linie um die Übung und das Verständnis der Materie).

    Bei folgender Funktion tritt eine AccessViolationException ein:

    [DllImport(avcodec_dll)]
    		public static extern int avcodec_encode_video(IntPtr avctx, IntPtr buf, int buf_size, IntPtr pict);
    

    Allerdings erst nach dem 2. Aufruf. Der 1. liefert zwar nicht das gewünschte Ergebnis, verursacht aber keine Exception und meldet auch von seiten FFmpeg keinen error.

    Ich weiss, dass es am ersten Pointer "avctx" liegt. Ich habe die Struktur, auf die der Pointer zeigt, vor und nach dem 1. Aufruf der Funktion verglichen, mit dem Ergebnis, dass sie absolut identisch sind, die Struktur innerhalb der C-Funktion also nicht verändert wird. Die Zugriffsverletzung wird in einer Codecspezifischen encode-funktion, auf die ein Funktionspointer verweist, verursacht.

    Dass ist soweit der Hintergrund. Ich erwarte von niemandem, mir jetzt eine Lösung zu präsentieren (ich denke, dazu wäre es unabdingbar, sowohl mein Programm, als auch den FFmpeg Sourcecode zu kennen). Falls aber jemand eine Strategie kennt, mit der ich die Lösung finden könnte, oder irgendwelche Anregungen, wäre ich dankbar, davon zu erfahren.
    Mich würde z.B. interessieren, ob es eine Möglichkeit gibt, die genau Adresse, bei welcher die Zugriffsverletzung eintrat, zu bekommen.

    mfg


  • Administrator

    Kannst du mir mal die vollständige Signatur der C Funktion zeigen, welche du aufrufst?

    Grüssli



  • natürlich:

    int avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size, const AVFrame *pict);
    

  • Administrator

    Argus Magnus schrieb:

    natürlich:

    int avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size, const AVFrame *pict);
    

    Ist das wirklich alles? Kein extern "C" oder noch ein Makro vor der Funktion?

    Ich mache mir nämlich sorgen wegen der Aufrufkonvention. In C und C++ ruft man Funktionen mit __cdecl auf. Die WinAPI ruft Funktionen mit __stdcall auf. Die beiden Aufrufkonventionen unterscheiden sich darin, wer am Ende den Stack aufräumt. Bei __stdcall macht dies der Callee, bei __cdecl macht dies der Caller. P/Invoke ist in erster Linie für die WinAPI ausgerichtet und ruft daher Funktionen standardmässig über __stdcall auf. Dies kann man allerdings abändern mit DllImportAttribute.CallingConvention .

    Ich rate übrigens noch dazu ExactSpelling auf true zu setzen, damit nicht vergeblich nach Funktionen mit einem A oder W Zusatz gesucht wird.

    Auch noch interessant dürfte EntryPoint sein. Dann kannst du in C# einen anderen Bezeichner verwenden und trotzdem die richtige Funktion aufrufen.

    Grüssli



  • nein, dass ist alles. Ich rufe andere Funktionen auf, ebenfalls ohne extern "C", die problemlos funktionieren und tun was man von Ihnen erwartet.
    CallingConvetion.Cdelc trägt leider nichts zur Lösung bei, habe aber gerade noch eine Frage dazu: Sollte ich in diesem Falle Funktionen aus einer C-Bibliothek (wie FFmpeg) immer mit cdelc aufrufen?

    Das mit EntryPoint wusste ich, lasse die namen aber bewusst so, da es sich vorerst um einen simplen Wrapper für die C-Funktionen handelt, damit kein durcheinander entsteht.

    Ich habe das Gefühl, das Problem sitzt tiefer. Es könnte auch am AVCodecContext liegen, dieser wird in einen C# struct gemarshallt, einige Memberwerte geändert und mit Marshal.StructureToPtr wieder zurück gemarshallt. Kann natürlich sein, dass da etwas nicht in Ordnung ist. Allerdings funktioniert diese Vorgehensweise mit anderen C-Funktionen problemlos. Ich könnte mir vorstellen, dass der AVCodecContext einen "fehlerhaften" Pointer/Funktionspointer enthält, über den die Funktion die Exception verursacht. Nur habe ich keine Ahnung, wie ich das überprüfen soll. Daher die Frage, nach der Möglichkeit, die genaue Adresse zu bekommen, auf welche die Funktion unberechtigterweise zugreifen wollte.

    mfg


  • Administrator

    Argus Magnus schrieb:

    CallingConvetion.Cdelc trägt leider nichts zur Lösung bei, habe aber gerade noch eine Frage dazu: Sollte ich in diesem Falle Funktionen aus einer C-Bibliothek (wie FFmpeg) immer mit cdelc aufrufen?

    Definitiv. C Funktionen müssen mit CallingConvention.Cdelc aufgerufen werden, wenn sie nicht anders gekennzeichnet sind.
    AccessViolationException kann vieles heissen. Womöglich erst dadurch ausgelöst, dass du mehrere Male die Funktionen eben falsch aufgerufen hast.

    Es kann aber natürlich auch sein, dass du was bei dieser Funktion komplett falsch machst. Dazu müsste man aber mehr darüber wissen, was die Funktion denn macht und was du wie übergibst. Wenn du den Fehler auf ein kleines Progrämmchen reduzieren könntest und dieses erklärst, könnte man dir wesentlich besser helfen.

    Auch noch helfen könnte dieses Tool (P/Invoke Interop Assistant):
    http://clrinterop.codeplex.com/

    Man sollte es allerdings mit Vorsicht geniessen.

    An die Adresse zu kommen dürfte schwer sein. Wenn du die Debug-Symbols von der ffmpeg Lib hast, könntest du diese noch in den Debug-Prozess einbeziehen. Unter den Projekteigenschaften und dann beim Tab Debug gibt es die Option "Enable unmanaged Code debugging". Dort ein Häckchen setzen. Wenn du nun eben die Debug-Symbols hast, kannst du in die C Funktion reinsteppen und somit deine Werte überprüfen.

    Sonst fällt mir nicht mehr viel ein. Vielleicht morgen dann wieder 😉

    Grüssli



  • Ich danke dir, leider habe ich keine Möglichkeit in der dll zu debuggen.
    Ich habe dass hier gefunden:
    http://libav-users.943685.n4.nabble.com/help-avcodec-encode-video-crashes-for-second-frame-td3163672.html
    Die Möglichkeit scheint zu bestehen, dass das ganze nicht unbedingt ein Fehler in meinem Code als Ursache hat.

    mfg



  • Okay, ich hab das Problem gelöst. War ein dummer Fehler meinerseits.. Ich hab an einer ganz anderen Stelle im Code vergessen, die Daten meines Structs mit den Daten des unmanaged structs auf den der IntPtr zeigte, zu synchronisieren...

    Trotzdem danke für die Hilfe


Anmelden zum Antworten