web-dev-qa-db-de.com

Häufige Gründe für Fehler in der Release-Version, die im Debug-Modus nicht vorhanden sind

Was sind die typischen Gründe für Fehler und ungewöhnliches Programmverhalten, die sich nur im Release-Kompilierungsmodus manifestieren, im Debug-Modus jedoch nicht auftreten?

59
Benny

Viele Male werden im Debug-Modus in C++ alle Variablen mit null initialisiert, während dies im Freigabemodus nicht der Fall ist, sofern dies nicht ausdrücklich angegeben ist.

Suchen Sie nach Debug-Makros und nicht initialisierten Variablen

Verwendet Ihr Programm Threading, dann kann die Optimierung auch einige Probleme im Freigabemodus verursachen.

Überprüfen Sie auch alle Ausnahmen, z. B. nicht direkt mit dem Freigabemodus, aber manchmal ignorieren wir nur einige kritische Ausnahmen, z. B. die Mem-Zugriffsverletzung in VC++. Das gleiche Problem kann jedoch zumindest in anderen Betriebssystemen wie Linux oder Solaris auftreten. Idealerweise sollte Ihr Programm solche kritischen Ausnahmen wie den Zugriff auf einen Nullzeiger nicht erkennen. 

29
Priyank Bolia

Eine häufige Falle verwendet einen Ausdruck mit Nebeneffekt in einem ASSERT.

18
Henrik

Andere Unterschiede können sein:

  • In einer nicht erfassten Sprache ist der Collector normalerweise aggressiverim Freigabemodus;
  • Das Layout des Gedächtnisses kann .__ oft unterschiedlich sein;
  • Der Speicher kann Auf andere Weise initialisiert werden (z. B. im Debug-Modus Auf Null gesetzt, oder bei der Veröffentlichung mehr Aggressiv verwendet werden);
  • Einheimische können befördert werden, um Werte in der Version zu registrieren. Dies kann Probleme mit Fließkomma-Werten verursachen.
9
stusmith

Ich wurde in der Vergangenheit von einer Reihe von Fehlern gebissen, die in Debug-Builds in Ordnung waren, in Release-Builds jedoch abstürzen. Es gibt viele zugrunde liegende Ursachen (natürlich auch die, die bereits in diesem Thread zusammengefasst wurden) und ich wurde von allen folgenden Ursachen entdeckt:

  • Member-Variablen oder Member-Funktionen in einem #ifdef _DEBUG, sodass eine Klasse in einem Debug-Build eine andere Größe hat. Manchmal wird #ifndef NDEBUG in einem Release-Build verwendet
  • Ebenso gibt es einen anderen #ifdef, der nur in einem der beiden Builds vorhanden ist
  • Die Debugversion verwendet Debugversionen der Systembibliotheken, insbesondere die Heap- und Speicherzuordnungsfunktionen
  • Eingebettete Funktionen in einem Release-Build
  • Reihenfolge der Aufnahme von Header-Dateien. Dies sollte keine Probleme verursachen, aber wenn Sie einen #pragma pack haben, der nicht zurückgesetzt wurde, kann dies zu unangenehmen Problemen führen. Ähnliche Probleme können auch bei der Verwendung von vorkompilierten Headern und erzwungenen Include auftreten
  • Caches: Möglicherweise verfügen Sie über Code wie Caches, die nur in Release-Builds verwendet werden, oder unterschiedliche Cachegrößen
  • Projektkonfigurationen: Die Debug- und Release-Konfigurationen können unterschiedliche Build-Einstellungen aufweisen (dies ist bei Verwendung einer IDE wahrscheinlich der Fall)
  • Race-Bedingungen, Timing-Probleme und verschiedene Nebenwirkungen, die durch Debug-Only-Code entstehen

Einige Tipps, die ich im Laufe der Jahre gesammelt habe, um Debug/Release-Fehlern auf den Grund zu gehen: 

  • Versuchen Sie, anomales Verhalten in einem Debug-Build zu reproduzieren, wenn Sie einen Komponententest schreiben und sogar noch besser schreiben können
  • Überlegen Sie sich, welche Unterschiede zwischen den beiden bestehen: Compilereinstellungen, Caches, nur Debug-Code. Versuchen Sie, diese Unterschiede vorübergehend zu minimieren
  • Erstellen Sie einen Release-Build mit deaktivierten Optimierungen (damit Sie wahrscheinlich mehr nützliche Daten im Debugger erhalten) oder einen optimierten Debug-Build. Durch die Minimierung der Änderungen zwischen Debug und Release können Sie mit größerer Wahrscheinlichkeit feststellen, welcher Unterschied den Fehler verursacht.
6
the_mandrill

Ja! Wenn Sie eine bedingte Kompilierung haben, kann es zu Timing-Fehlern kommen (optimierter Versionscode, nicht optimierter Debug-Code), Wiederverwendung des Speichers im Vergleich zum Debug-Heap.

3
Simeon Pilgrim

Es kann, besonders wenn Sie im C-Bereich sind.

Eine Ursache könnte sein, dass die DEBUG-Version möglicherweise Code hinzufügt, um nach verweisenen Zeigern zu suchen und Ihren Code irgendwie vor Abstürzen zu schützen (oder sich falsch zu verhalten). In diesem Fall sollten Sie Warnungen und andere Meldungen, die Sie von Ihrem Compiler erhalten, sorgfältig prüfen.

Eine andere Ursache könnte die Optimierung sein (die normalerweise für Release-Versionen und für Debugging aktiviert ist). Der Code und das Datenlayout wurden möglicherweise optimiert. Während Ihr Debugging-Programm beispielsweise nur auf nicht verwendeten Speicher zugreifen konnte, versucht die Release-Version jetzt, auf reservierten Speicher zuzugreifen oder sogar auf Code zu verweisen!

EDIT: Ich sehe, dass andere es erwähnt haben: Natürlich können Sie ganze Codeabschnitte haben, die bedingt ausgeschlossen sind, wenn Sie nicht im DEBUG-Modus kompilieren. Wenn das der Fall ist, hoffe ich, dass es sich wirklich um einen Debugging-Code handelt und nicht unbedingt von entscheidender Bedeutung für die Korrektheit des Programms selbst!

3
Remo.D

Die CRT-Bibliotheksfunktionen verhalten sich im Debuggen gegenüber dem Release (/ MD vs./MDd) unterschiedlich.

Zum Beispiel füllen die Debug-Versionen häufig Puffer auf, die Sie an die angegebene Länge übergeben, um Ihren Anspruch zu überprüfen. Beispiele sind strcpy_s, StringCchCopy, usw. Auch wenn die Zeichenfolgen früher enden, ist Ihre szDest besser - n Byte lang!

3
Alex Budovski

Sicher, zum Beispiel, wenn Sie Konstruktionen wie verwenden

#if DEBUG

//some code

#endif
2
Max Galkin

Auch wenn Sie keine bedingte Kompilierung wie #if DEBUG verwenden, ist der Compiler in .NET noch viel liberaler mit Optimierungen im Freigabemodus als im Debug-Modus, was nur zu Fehlern führen kann.

2

Sie müssten viel mehr Informationen geben, aber es ist möglich. Es hängt davon ab, was Ihre Debug-Version macht. Möglicherweise haben Sie Protokollierungen oder zusätzliche Prüfungen, die nicht in eine Release-Version kompiliert werden. Diese Debugging-Codepfade können unbeabsichtigte Nebeneffekte haben, die den Status ändern oder Variablen auf merkwürdige Weise beeinflussen. Debug-Builds werden normalerweise langsamer ausgeführt. Dies kann sich auf das Threading auswirken und die Race-Bedingungen ausblenden. Dasselbe gilt für einfache Optimierungen von einem Release-Compile. Es ist möglich (obwohl dies heutzutage unwahrscheinlich ist), dass ein Release-Compile als Optimierung etwas Kurzschluss verursacht.

1
blowdart

Ohne weitere Details gehe ich davon aus, dass "nicht OK" bedeutet, dass es entweder nicht kompiliert wird oder zur Laufzeit einen Fehler ausgibt. Überprüfen Sie, ob Sie über einen Code verfügen, der auf die Kompilierungsversion angewiesen ist, entweder über Anweisungen #if DEBUG oder über Methoden, die mit dem Attribut Conditional gekennzeichnet sind.

1
Konamiman

In einer nicht ungültigen Funktion sollten alle Ausführungspfade mit einer return-Anweisung enden. 

Wenn Sie im Debug-Modus vergessen, einen solchen Pfad mit einer return-Anweisung zu beenden, gibt die Funktion standardmäßig 0 zurück.

Im Freigabemodus gibt Ihre Funktion jedoch möglicherweise Abfallwerte zurück, die sich auf die Ausführung Ihres Programms auswirken können.

1
loudandclear

Es gibt Compiler-Optimierungen, die gültigen Code beschädigen können , weil sie zu aggressiv sind.

Versuchen Sie, Ihren Code mit weniger aktivierten Optimierungen zu kompilieren.

1
Georg Schölly

Dies ist möglich, wenn Sie über eine bedingte Kompilierung verfügen, so dass sich der Debug-Code und der Freigabecode unterscheiden und der Code einen Fehler enthält, der nur im Freigabemodus verwendet wird.

Ansonsten ist es nicht möglich. Es gibt Unterschiede bei der Kompilierung von Debug-Code und Release-Code und bei der Ausführung von Code, wenn er unter einem Debugger ausgeführt wird oder nicht. Wenn jedoch einer dieser Unterschiede etwas anderes als einen Leistungsunterschied verursacht, war das Problem schon immer vorhanden.

In der Debug-Version tritt der Fehler möglicherweise nicht auf (weil das Timing oder die Speicherzuordnung unterschiedlich sind). Dies bedeutet jedoch nicht, dass der Fehler nicht vorhanden ist. Es kann auch andere Faktoren geben, die nicht mit dem Debug-Modus zusammenhängen, der das Timing des Codes ändert, was dazu führt, dass der Fehler auftritt oder nicht, aber es läuft alles darauf hinaus, dass der Fehler nicht auftritt, wenn der Code korrekt ist in einer der Situationen.

Nein, die Debug-Version ist nicht in Ordnung, nur weil Sie sie ausführen können, ohne einen Fehler zu erhalten. Wenn ein Fehler auftritt, wenn Sie ihn im Freigabemodus ausführen, liegt dies nicht am Freigabemodus, sondern daran, dass der Fehler von Anfang an vorhanden war.

1
Guffa

Ich erinnere mich an die Zeit, als wir dll und pdb in c/c ++ bauten. 

Ich erinnere mich daran:

  • Durch das Hinzufügen von Protokolldaten könnte der Fehler irgendwann verschoben oder ausgeblendet werden, oder es wird ein völlig anderer Fehler angezeigt.
  • Viele dieser Fehler wurden aufgrund der Char-Zuordnung in strcpy und strcat und Arrays von char [] usw. verursacht. 
  • Wir haben einiges herausgearbeitet, indem wir Bounds Checker ausgeführt und einfach die Speicherzuordnung/Dealloc-Probleme behoben haben. 
  • Oft haben wir den Code systematisch durchgearbeitet und eine Char-Zuordnung festgelegt (wie in allen Dateien). 
  • Auf jeden Fall bezieht sich dies auf die Speicherzuordnung und -verwaltung sowie Einschränkungen und Unterschiede zwischen dem Debug-Modus und dem Freigabemodus.

Und hoffte dann auf das Beste.

Manchmal habe ich vorübergehend Debug-Versionen von DLLs an Clients ausgeliefert, um die Produktion nicht zu behindern, während ich an diesen Fehlern arbeite.

0
Sassine Jaoude

Ich habe das gerade erlebt, als ich eine Assembly-Funktion anrief, die die vorherigen Werte der Register nicht wiederhergestellt hat. 

In der "Release" -Konfiguration kompilierte VS mit/O2, wodurch der Code auf Geschwindigkeit optimiert wurde. Einige lokale Variablen, bei denen lediglich eine Zuordnung zu CPU-Registern (zur Optimierung) vorgenommen wurde, die mit der zuvor genannten Funktion gemeinsam genutzt wurden, führen zu schwerwiegenden Speicherbeschädigungen.

Wie auch immer, ob Sie nicht indirekt mit CPU-Registern irgendwo in Ihrem Code herumspielen.

0
mycelo

Es ist möglich. Wenn dies der Fall ist und keine bedingte Kompilierung erforderlich ist, können Sie ziemlich sicher sein, dass Ihr Programm falsch ist und nur im Debug-Modus arbeitet, weil zufällige Speicherinitialisierungen oder sogar das Layout im Speicher vorhanden sind!

0
UncleZeiv

Ein anderer Grund könnten DB-Aufrufe sein . Speichern und aktualisieren Sie denselben Datensatz mehrmals in demselben Thread, Manchmal zum Aktualisieren . Möglicherweise ist das Update fehlgeschlagen oder funktionierte nicht wie erwartet, da der vorherige Befehl zum Erstellen noch vorhanden war Bei der Verarbeitung und für das Update konnte der Db-Aufruf keinen Datensatz finden. Dies geschieht nicht in Debug, da der Debugger vor dem Landen alle ausstehenden Aufgaben abschließt.

0