Return value im Falle von Try-Catch

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Benutzeravatar
Krishty
Establishment
Beiträge: 8268
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Return value im Falle von Try-Catch

Beitrag von Krishty »

BeRsErKeR hat geschrieben:Wobei ich auch schon die Erfahrung gemacht habe, dass Compiler mitunter sehr komische Sachen machen, z.B. Codeteile wegoptimieren, weil sie denken dass sie nicht gebraucht werden und wenn man sie dann nutzen will knallts.
Glaube ich erst, wenn ich es sehe. Wollte mir gestern schon jemand weismachen, und dann war es eine falsch formulierte Schleifenbedingung. Klar; ich hatte ja selber schon einen Bug, dass ein Register fälschlicherweise als ungenutzt eingestuft wurde und futtsch war – aber komplette Textstellen? Niemals, jedenfalls nicht mit GCC oder Visual C++ nach 6.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: Return value im Falle von Try-Catch

Beitrag von BeRsErKeR »

Krishty hat geschrieben:
BeRsErKeR hat geschrieben:Wobei ich auch schon die Erfahrung gemacht habe, dass Compiler mitunter sehr komische Sachen machen, z.B. Codeteile wegoptimieren, weil sie denken dass sie nicht gebraucht werden und wenn man sie dann nutzen will knallts.
Glaube ich erst, wenn ich es sehe. Wollte mir gestern schon jemand weismachen, und dann war es eine falsch formulierte Schleifenbedingung. Klar; ich hatte ja selber schon einen Bug, dass ein Register fälschlicherweise als ungenutzt eingestuft wurde und futtsch war – aber komplette Textstellen? Niemals, jedenfalls nicht mit GCC oder Visual C++ nach 6.
Glaub mir wir hatten viel Freude auf Arbeit mit dem gcc 4.4.X. Die Optimierung hat mitunter sehr lustige Dinge getan. Und das Wegoptimieren konnte man auch gut im ASM angucken. Die Codeteile waren tatsächlich weg.

Noch schöner war:

Code: Alles auswählen

float f = 0.33f * (rand() % 10000);
printf("out: %0.6f\n", f);
printf("out: %0.6f\n", f);
Bei diesem Code unterschieden sich die beiden printf-Ausgaben. Allerdings waren die Werte nur geringfügig unterschiedlich. Unser Wundermittel heißt volatile. Deklariert man f als solches ist das Problem behoben, genauso wenn man die Optimierung ausschaltet. Wir haben sehr viele Dinge testweise mit volatile gefixt, weil die gcc 4.4.X Serie scheinbar sehr viele Probleme mit der Optimierung hat.

In unserem Projekt steht nun ein Präprozessor-Makro, welches einen #error schmeißt sofern man eine 4.4.X Version von gcc nutzt und die Optimierung aktiv ist.
Ohne Input kein Output.
Benutzeravatar
Krishty
Establishment
Beiträge: 8268
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Return value im Falle von Try-Catch

Beitrag von Krishty »

Aua. Ist ja grauenhaft! Habe auch keine Vorstellung, wie sowas passieren kann.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: Return value im Falle von Try-Catch

Beitrag von BeRsErKeR »

Das Problem an der printf-Sache war, dass wir eigentlich die Übertragung von floats im BE-Format mit spezieller Codierung realisieren wollten und dann den Wert auf beiden Seiten (eine Seite Sun -> BE, andere Seite Ubuntu -> LE) per printf ausgegeben haben. Wir haben 2 Tage gesucht und dachten die Übertragung sei fehlerhaft. Dann haben wir gemerkt, dass sich der Wert bereits nach dem ersten printf auf der Senderseite ändert. Gleiches passierte im Übrigen auch bei std::cout. Anfangs dachten wir, dass die vaargs vom printf irgendwas kaputt hauen, aber als dann auch std::cout in die Knie ging kannten wir eigentlich schon die Lösung: volatile. :D
Ohne Input kein Output.
Benutzeravatar
Krishty
Establishment
Beiträge: 8268
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Return value im Falle von Try-Catch

Beitrag von Krishty »

Das kann ja wieder was anderes sein – dass tan(x) != tan(x) ist (weil die CPU den ersten Wert in eine float oder double zurückschreibt bevor sie den zweiten ausrechnet, und dabei vom 80-Bit-Zwischenergebnis 16 oder 48 Bits verloren gehen während der Zweite noch mit voller Präzision im FPU-Revolver liegt), ist allgemein bekannt und zulässig. Bei printf() werden auch vor der Übergabe alle Operanden zu 64 Bits konvertiert; [bzzzz ich habe ganz überlesen, dass es mit cout auch nicht ging] es könnte also tatsächlich der Fehler sein, dass durch globale Optimierungen einige Zahlen auf den Stapelspeicher gespült werden während andere in der FPU bleiben.

Da oben sah es aber aus, als hätte der Compiler nicht kapiert, dass rand() eine Wirkung hat und er deshalb den Funktionsaufruf nicht duplizieren darf. Das wäre ein Kaliber, wodurch der ganze Compiler unbrauchbar würde.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: Return value im Falle von Try-Catch

Beitrag von BeRsErKeR »

Ja alle diese Fälle haben wir auch vermutet. Letztlich handelt es sich scheinbar wirklich um ersteren Sachverhalt. Uns fiel recht schnell auf, dass der Wert nach dem ersten printf (also bei weiteren Ausgaben) genau dem Wert entspricht, den man erhält, wenn man den float-Wert vorher in einen double castet (bei double gab es übrigens keine Abweichungen). Es war auch immer so, dass nur die erste Ausgabe fehlerhaft war.

Das merkwürdige ist halt, dass bei der Übergabe von f an printf oder cout eigentlich eine Kopie übergeben werden müsste. Somit kann sich f theoretisch nicht ändern und jeder printf-Aufruf sollte identisch sein. Allerdings hatten wir dann auch schnell die FPU im Verdacht, die zusammen mit der Optimierung für die Abweichungen sorgt. Auch waren die Abweichungen zu gering um nicht von Rundungs- bzw. Umwandlungsfehlern auszugehen.

Prinzipiell finde ich es aber schon unglücklich, wenn ein und derselbe Funktionsaufruf unterschiedliche Outputs liefert, jedenfalls bei Funktionen, die nichts anderes erwarten lassen. Von mir aus kann er den Wert ja in einen double casten, allerdings sollte der Output immer identisch sein. Auch beim 1. Aufruf.

Merkwürdig war auch, dass ein cout-Aufruf den ersten printf-Aufruf gefixt hat und umgekehrt.
Ohne Input kein Output.
Benutzeravatar
Krishty
Establishment
Beiträge: 8268
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Return value im Falle von Try-Catch

Beitrag von Krishty »

BeRsErKeR hat geschrieben:Das merkwürdige ist halt, dass bei der Übergabe von f an printf oder cout eigentlich eine Kopie übergeben werden müsste. Somit kann sich f theoretisch nicht ändern und jeder printf-Aufruf sollte identisch sein. Allerdings hatten wir dann auch schnell die FPU im Verdacht, die zusammen mit der Optimierung für die Abweichungen sorgt. Auch waren die Abweichungen zu gering um nicht von Rundungs- bzw. Umwandlungsfehlern auszugehen.
printf() castet, wie gesagt, zu 64 Bits und bei cout ist es oft so, dass man der Wartbarkeit halber ein- und dieselbe Routine benutzt, um sowohl float als auch double in einen String zu schreiben. Konvertiert wird die Zahl also (leider) immer irgendwie. Ziemlich ärgerlich, wenn dann sowas passiert.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: Return value im Falle von Try-Catch

Beitrag von BeRsErKeR »

Im gcc 4.5.X war der Fehler übrigens verschwunden. Es war also definitiv ein compilerspezifischer Bug in der Optimierung. Das Schlimme an solchen Bugs ist halt dass man einen Haufen Zeit sinnlos verschwenden muss und kurz davor ist den kompletten Code umzuschreiben.
Ohne Input kein Output.
Antworten