AccessViolationException Lesen von Arbeitsspeicher, der in C ++ - Anwendung von C ++ / CLI DLL zugewiesen wird

8

Ich habe einen C ++ - Client für eine C ++ / CLI-DLL, die eine Reihe von C # -Dlls initialisiert.

Das hat früher funktioniert. Der Code, der fehlschlägt, hat sich nicht geändert. Der Code, der geändert wurde, wird nicht vor dem Auslösen der Ausnahme aufgerufen. Meine Kompilierungsumgebung hat sich geändert, aber das erneute Kompilieren auf einem Computer mit einer der alten ähnlichen Umgebung ist immer noch fehlgeschlagen. (BEARBEITEN: wie wir in der Antwort sehen, ist dies nicht ganz richtig, ich habe nur die Bibliothek in der alten Umgebung neu kompiliert, nicht die Bibliothek und den Client zusammen. Die Client-Projekte wurden aktualisiert und konnten nicht einfach zurückgehen.)

Jemand außer mir hat die Bibliothek neu kompiliert und wir haben Probleme mit der Speicherverwaltung bekommen. The pointer passed in as a String must not be in the bottom 64K of the process's address space. Ich habe es neu kompiliert, und alles funktionierte gut ohne Codeänderungen. (Alarm # 1) Vor kurzem wurde es neu kompiliert, und Speicherverwaltungsprobleme mit Zeichenfolgen erschienen wieder, und dieses Mal gehen sie nicht weg. Der neue Fehler ist Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

Ich bin mir ziemlich sicher, dass das Problem nicht dort liegt, wo ich die Ausnahme sehe, der Code hat sich zwischen den erfolgreichen und den fehlgeschlagenen Builds nicht geändert, aber wir sollten das überprüfen, um abgeschlossen zu sein. Ignoriere die Namen der Dinge, ich habe nicht viel Kontrolle über das Design dessen, was es mit diesen Strings macht. Und sorry für die Verwirrung, aber beachte, dass _bridge und bridge unterschiedliche Dinge sind. Viele Codezeilen fehlen, weil diese Frage schon zu lang ist.

In Bibliothek definiert:

%Vor%

In der Client-Funktion:

%Vor%

Beachten Sie, dass der Aufruf der Bibliothek, die abstürzt, im selben Bereich liegt wie die Vektordeklaration, die Strukturdeklaration, die Zeichenfolgenzuweisung und das Vektor-Pushback Es gibt keine Threading-Aufrufe in diesem Codeabschnitt, aber es werden andere Threads ausgeführt, die andere Dinge ausführen. Hier gibt es keine Zeigermathematik, es gibt keine Heapzuweisungen in dem Bereich außer vielleicht in der Standardbibliothek.

Ich kann den Code bis zum Aufruf Bridge_GetConfiguredDefaultsImplementationPointer im Debugger ausführen und der Inhalt des Vektors configs im Debugger korrekt aussehen.

Zurück in der Bibliothek, in der ersten Unterfunktion, wo der Debugger nicht scheint, habe ich die fehlerhafte Aussage in mehrere Konsolendrucke aufgeteilt.

%Vor%

Ich bekomme die gleiche Ausnahme beim Zugriff von bee , wenn ich die newConfigs[i].bee über die Zuweisung von temp verschiebe oder die Listendeklaration / -zuordnung auskommentiere.

Nur als Hinweis, dass die std :: string in einer Struktur in einem Vektor am Zielort angekommen sein soll ok

Warum diese Ausnahme nicht von meinem try / catch

abgefangen wird

Ссылка

Generische AccessViolationException-bezogene Fragen

Vorschläge in obigen Fragen

  • Wechseln Sie zu .net 3.5, ändern Sie die Zielplattform - diese Lösungen könnten ernsthafte Probleme mit einer großen Multiprojektlösung haben.
  • HandleProcessCorruptedStateExceptions - funktioniert nicht in C ++, diese Dekoration ist für C #, das Erfassen dieses Fehlers könnte sowieso eine sehr schlechte Idee sein
  • Change legacyCorruptedStateExceptionsPolicy - hier geht es darum, den Fehler abzufangen, nicht zu verhindern
  • Installiere .NET 4.5.2 - kann nicht, habe schon 4.6.1. Die Installation von 4.6.2 hat nicht geholfen. Das erneute Kompilieren auf einem anderen Computer, auf dem 4.5 oder 4.6 nicht installiert war, hat nicht geholfen.(Obwohl dies vor der Installation von Visual Studio 2013 auf meinem Computer kompiliert und ausgeführt wurde, was stark darauf hindeutet, dass die .NET-Bibliothek ein Problem darstellt?)
  • VSDebug_DisableManagedReturnValue - Ich sehe das nur in Bezug auf einen bestimmten Absturz im Debugger erwähnt, und die Hilfe von Microsoft sagt, dass andere AccessViolationException-Probleme wahrscheinlich nicht verwandt sind. ( Ссылка )
  • Einstellungen der Comodo Firewall ändern - Ich benutze diese Software nicht
  • Ändern Sie den gesamten Code in verwalteten Speicher - keine Option. Das gesamte Design des Aufrufs von C # von C ++ bis C ++ / CLI ist resistent gegenüber Änderungen. Ich wurde speziell gebeten, es so zu gestalten, um vorhandenen C # -Code aus bestehendem C ++ - Code zu nutzen.
  • Stellen Sie sicher, dass Speicher zugewiesen ist - Speicher sollte auf dem Stapel im C ++ - Client zugewiesen werden. Ich habe versucht, den Vektor nicht zu einem Bezugsparameter zu machen, um eine Vektorkopie in explizit Bibliothek kontrollierten Speicherplatz zu zwingen, hat nicht geholfen.
  • "Zugriffsverletzungen in nicht verwaltetem Code, die auf verwalteten Code übergehen, werden immer in eine AccessViolationException eingeschlossen." - Tatsache, keine Lösung.
Denise Skidmore 02.12.2016, 22:12
quelle

3 Antworten

8
  

Aber es war die Nichtübereinstimmung, nicht die spezifische Version, die das Problem war

Ja, das ist das Gesetz des schwarzen Buchstabens in VS. Sie haben leider nur die Gegenmaßnahmen vermisst, die in VS2012 eingebaut wurden, um diesen Fehler in einen diagnostizierbaren Linkerfehler umzuwandeln. Zuvor (und in VS2010) würde die CRT ihren eigenen Heap mit HeapAlloc () zuweisen. Jetzt (in VS2013) verwendet es den Standard-Prozess-Heap, der von GetProcessHeap () zurückgegeben wird.

Was an sich schon ausreicht, um einen AVE auszulösen, wenn Sie Ihre Anwendung unter Vista oder höher ausführen, wird Speicher von einem Heapspeicher zugewiesen und von einem anderen Heap freigegeben. Ein Debugger bricht zur Laufzeit beim Debuggen mit aktiviertem Debug Heap ab.

Dies ist nicht dort, wo es endet, ein anderes wichtiges Problem ist, dass das std :: string-Objekt-Layout nicht das gleiche zwischen den Versionen ist. Etwas, das Sie mit einem kleinen Testprogramm entdecken können:

%Vor%
  • VS2010 Debug: 32
  • VS2010 Release: 28
  • VS2013 Debug: 28
  • VS2013 Release: 24

Ich habe eine vage Erinnerung an Stephen Lavavej, der die Reduktion der std :: string-Objektgröße erwähnt, die sehr viel als Feature präsentiert wird, aber ich kann sie nicht finden. Die zusätzlichen 4 Byte im Debug-Build werden durch die Iterator-Debugging-Funktion verursacht. Sie kann in den Präprozessor-Definitionen mit _HAS_ITERATOR_DEBUGGING=0 deaktiviert werden. Keine Funktion, die Sie schnell wegwerfen möchten, aber das Mischen von Debug- und Release-Builds der EXE und ihrer DLLs ist ziemlich tödlich.

Unnötig zu sagen, dass die verschiedenen Objektgrößen ernsthaft Bytes sind, wenn das Config-Objekt in einer DLL erstellt wird, die mit einer Version der C ++ - Standardbibliothek erstellt und in einer anderen verwendet wird. Viele Missgeschicke, die einfachste ist, dass der Code einfach das Config :: bee-Element vom falschen Offset liest. Ein AVE ist (fast) garantiert. Es gibt viel mehr Ärger, wenn Code den kleinen Geschmack des Config-Objekts zuweist, aber den großen Flavor von std :: string schreibt, der den Heap oder den Stack-Frame zufällig verfälscht.

Nicht mischen.

    
Hans Passant 11.12.2016, 19:09
quelle
6

Ich glaube, dass 2013 viele Änderungen in den internen Datenformaten von STL-Containern eingeführt wurden, um die Speicherauslastung zu reduzieren und die Leistung zu verbessern. Ich weiß, vector wurde kleiner, und string ist im Grunde eine verherrlichte vector<char> .

Microsoft erkennt die Inkompatibilität an:

  

"Um neue Optimierungen und Debugging-Prüfungen zu ermöglichen, Visual Studio   Implementierung der C ++ - Standardbibliothek bricht absichtlich binär   Kompatibilität von einer Version zur nächsten. Daher, wenn das C ++   Standard-Bibliothek verwendet wird, Objektdateien und statische Bibliotheken, die sind   kompiliert mit verschiedenen Versionen können nicht in einer Binärdatei (EXE   oder DLL), und C ++ - Standardbibliothek-Objekte können nicht zwischen übergeben werden   Binärdateien, die mit verschiedenen Versionen kompiliert werden. "

Wenn Sie std::* -Objekte zwischen ausführbaren Dateien und / oder DLLs übergeben, müssen Sie unbedingt sicherstellen, dass sie dieselbe Version des Compilers verwenden. Es wäre gut beraten, wenn Ihr Client und seine DLLs beim Start in irgendeiner Weise verhandeln und alle verfügbaren Versionen (z. B. Compiler-Version + Flags, Boost-Version, DirectX-Version usw.) vergleichen, damit Sie solche Fehler schnell finden. Stellen Sie es sich als eine modulübergreifende Behauptung vor.

Wenn Sie bestätigen möchten, dass dies das Problem ist, können Sie einige der Datenstrukturen, die Sie hin und her übergeben, auswählen und deren Größe im Client im Vergleich zu den DLLs überprüfen. Ich vermute, dass Ihre Config -Klasse oben in einem der Fehlerfälle anders registriert wird.

Ich möchte auch erwähnen, dass es in erster Linie eine schlechte Idee ist, intelligente Container in DLL-Aufrufen zu verwenden. Sofern Sie nicht garantieren können, dass die App und die DLL nicht versuchen, die internen Puffer der anderen Container freizugeben oder neu zuzuweisen, könnten Sie leicht Probleme mit Heap-Problemen bekommen, da die App und DLL jeweils ihren eigenen internen C ++ - Heap haben. Ich denke, dass dieses Verhalten bestenfalls undefiniert ist. Auch das Übergeben von const& Argumenten kann in seltenen Fällen immer noch zu einer Neuzuweisung führen, da const einen Compiler nicht daran hindert, mit mutable internals zu spielen.

    
Aiken Drum 09.12.2016 15:34
quelle
0

Sie scheinen Speicherkorruption zu haben. Microsoft Application Verifier ist bei der Suche nach Korruption von unschätzbarem Wert. Benutze es, um deinen Fehler zu finden:

  1. Installieren Sie es auf Ihrem Dev-Rechner.
  2. Fügen Sie Ihre exe hinzu.
  3. Wählen Sie nur Basics\Heaps .
  4. Drücken Sie Speichern. Es spielt keine Rolle, ob Sie den Application Verifier geöffnet lassen.
  5. Führen Sie Ihr Programm ein paar Mal aus.
  6. Wenn es abstürzt, debugge es und diesmal zeigt der Absturz auf dein Problem und nicht nur auf irgendeinen zufälligen Ort in deinem Programm.

PS: Es ist eine gute Idee, den Application Verifier jederzeit für Ihr Entwicklungsprojekt zu aktivieren.

    
Codeguard 05.12.2016 18:02
quelle