(erledigt)[C++] catch zerstört Funktionsparameter
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
(erledigt)[C++] catch zerstört Funktionsparameter
Erledigt — es handelt sich um einen Compiler-Bug, der in catch-Blöcken auftritt, wenn lokale Variablen genutzt werden, die Ausrichtung erfordern (also __declspec(align(#))-dekoriert sind). Es wird empfohlen, bei solchen Funktionen /Og per #pragma optimize zu deaktivieren oder die Funktionsparameter in lokale Variablen zu kopieren. Für VC 2012 wird der Fehler behoben werden.
Hi,
Ich habe eine Funktion, die ab und zu eine Exception fängt und danach fortsetzt. Wenn das geschieht, sind die Funktionsparameter um 20 Bytes verschoben – aber ohne Inhalt; was bedeutet, dass es bei der Benutzung sofort kracht. Lokale Variablen bleiben unberührt und intakt.
Das Problem taucht nur in Release-Builds (unter x86 und x64) auf. Omit Frame Pointer und Stack-Checks zeigen keinen Effekt. In Debug-Builds läuft alles rund; alle Sicherheitsfeatures sind eingeschaltet und keins meckert.
Es ist egal, was ich fange (auch throw 0; führt zu dem Fehler). Ich habe – so weit es ging – den Code vereinfacht, aber ohne Resultat. Ich würde fast an einen Compiler-Fehler glauben, aber dass mir zwei unterschiedliche Optimizer in zwei Tagen in derselben Funktion mit je einem Bug das Leben schwermachen ist sogar für mich unwahrscheinlich. Außerdem kann ich das Problem weder bei einem anderen Aufruf noch mit einer anderen Funktion reproduzieren.
Also: Was tun, um dem Fehler auf die Schliche zu kommen?
Gruß, Ky
Hi,
Ich habe eine Funktion, die ab und zu eine Exception fängt und danach fortsetzt. Wenn das geschieht, sind die Funktionsparameter um 20 Bytes verschoben – aber ohne Inhalt; was bedeutet, dass es bei der Benutzung sofort kracht. Lokale Variablen bleiben unberührt und intakt.
Das Problem taucht nur in Release-Builds (unter x86 und x64) auf. Omit Frame Pointer und Stack-Checks zeigen keinen Effekt. In Debug-Builds läuft alles rund; alle Sicherheitsfeatures sind eingeschaltet und keins meckert.
Es ist egal, was ich fange (auch throw 0; führt zu dem Fehler). Ich habe – so weit es ging – den Code vereinfacht, aber ohne Resultat. Ich würde fast an einen Compiler-Fehler glauben, aber dass mir zwei unterschiedliche Optimizer in zwei Tagen in derselben Funktion mit je einem Bug das Leben schwermachen ist sogar für mich unwahrscheinlich. Außerdem kann ich das Problem weder bei einem anderen Aufruf noch mit einer anderen Funktion reproduzieren.
Also: Was tun, um dem Fehler auf die Schliche zu kommen?
Gruß, Ky
Zuletzt geändert von Krishty am 22.12.2010, 00:55, insgesamt 2-mal geändert.
- CodingCat
- Establishment
- Beiträge: 1857
- Registriert: 02.03.2009, 21:25
- Wohnort: Student @ KIT
- Kontaktdaten:
Re: [C++] catch zerstört Funktionsparameter
Wie sieht denn der vereinfachte Code aus? Könnten irgendwelche Destruktoren der durch die Exception frühzeitig zerstörten Objekte Amok laufen? Was genau wird verschoben? Zeigen die Funktionsparameter nach der Exception an die falsche Stelle (um 20 Bytes verschoben), oder ist der Inhalt um 20 Bytes verschoben und die Parameter zeigen weiterhin an die alte Stelle (OK, das macht wenig Sinn, aber liegt der Inhalt noch irgendwo)? Überquert die Exception Dll-Grenzen?
Du könntest die Release-Konfiguration duplizieren und sie Feature für Feature zur Debug-Konfiguration umbauen, bis es nicht mehr kracht.
Du könntest die Release-Konfiguration duplizieren und sie Feature für Feature zur Debug-Konfiguration umbauen, bis es nicht mehr kracht.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Re: [C++] catch zerstört Funktionsparameter
Das wäre meiner Meinung nach auch erst einmal der richtige Weg. Wenn es schlecht läuft, ist es halt genau der Optimierungsschalter - wobei die ja (so weit ich weiß) nur Schalter für kleinere Optimierungseinstellungen sind, und die man auch noch einmal gesondert durchgehen könnte. Ohne Minimalbeispiel kann man dazu wohl relativ schlecht etwas sagen ...CodingCat hat geschrieben:Du könntest die Release-Konfiguration duplizieren und sie Feature für Feature zur Debug-Konfiguration umbauen, bis es nicht mehr kracht.
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] catch zerstört Funktionsparameter
Der vereinfachte Code sieht relativ einfach aus:(Ich habe nur die Adresse des einen Parameters genommen, weil die Adressen der anderen transparent sind, sind ja Referenzen.) Dieser aufrufende Konstruktor ist __forceinline deklariert und der Fehler verschwindet, sobald ich das wegnehme, wie ich eben herausgefunden habe (die Funktion selber wird aber nicht geinlined). Vielleicht kann ich es mit diesem Wissen endlich reproduzieren.
Das mit der Konfiguration möchte ich als allerletzte Möglichkeit offen halten, weil acht statische/dynamische Bibliotheken dranhängen und ich die Einstellungen überall gleichzeitig samt Neukompilierung vornehmen muss, was dauert und nervt :/
Noch was: Ich konnte das Problem kurzzeitig umschiffen, indem ich die Parameter in lokale Variablen kopiert habe. Nachdem ich einen Typnamen geändert habe (!!!) optimiert der Compiler die lokalen Variablen aber weg und alles ist beim alten.
Code: Alles auswählen
template <
typename IShader
> class TCShader
: private COM::TIReference<IShader>
{
…
public:
static // named constructor
TCShader<IShader> Cached(
::ID3D11Device & ItsGPU,
CUTF8String const & ItsSourceFilesPath,
CASCIICharacter const ItsEntryPointsName[]
) {
CASCIICharacter Profile[8];
// &ItsEntryPointsName: 0x003ff52c
// &Profile[0]: 0x003ff460
try {
throw 0;
} catch(...) {
// &ItsEntryPointsName: 0x013178a8
// &Profile[0]: 0x003ff460
// Alle Parameter zeigen auf Müll
}
// &ItsEntryPointsName: 0x003ff518
// &Profile[0]: 0x003ff460
// Alle Parameter zeigen auf Müll
…
}
};
// Aufruf von einem Konstruktor aus:
// Die hier gehen noch gut:
, MyTrivialTonemappingOperator(D3D11::CComputeShader::Cached(MyD3DDevice.Device, CUTF8String("Direct3D 11\\tonemapping operator (trivial) 5.hlsl"), "ProcessPixel"))
, MyHumanTonemappingOperator(D3D11::CComputeShader::Cached(MyD3DDevice.Device, CUTF8String("Direct3D 11\\tonemapping operator (human) 5.hlsl"), "ProcessPixel"))
// PENG vollindiefresse:
, MyHorizontal512SampleFFTShader(D3D11::CComputeShader::Cached(MyD3DDevice.Device, CUTF8String("Direct3D 11\\FFT.hlsl"), "FFT_512_horizontal"))
Das mit der Konfiguration möchte ich als allerletzte Möglichkeit offen halten, weil acht statische/dynamische Bibliotheken dranhängen und ich die Einstellungen überall gleichzeitig samt Neukompilierung vornehmen muss, was dauert und nervt :/
Noch was: Ich konnte das Problem kurzzeitig umschiffen, indem ich die Parameter in lokale Variablen kopiert habe. Nachdem ich einen Typnamen geändert habe (!!!) optimiert der Compiler die lokalen Variablen aber weg und alles ist beim alten.
- kimmi
- Moderator
- Beiträge: 1412
- Registriert: 26.02.2009, 09:42
- Echter Name: Kim Kulling
- Wohnort: Luebeck
- Kontaktdaten:
Re: [C++] catch zerstört Funktionsparameter
Kannst du den Offset durch das Variieren von Strings, lokaler Varaiblen whatever modifizieren ( spricht statt 20 Bytes 14 Bytes )? Wenn ja: schau dir die mal genauer an. Was sagt AppVerifier hierzu? Hast du deine lokalen Variablen schon mal volatile gemacht, ändert was was?
Gruß Kimmi
Gruß Kimmi
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] catch zerstört Funktionsparameter
Werde das ausprobieren, sobald ich zu Hause bin. Vorher aber eine Frage am Rande: Wie kommst du auf 14 Bytes?
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] catch zerstört Funktionsparameter
Soo …
Das Offset lässt sich nicht modifizieren. Ich habe lokale Variablen hinzugefügt, entfernt, volatile gemacht (soweit es ging – bei Referenzen ist es ja z.B. unmöglich), Code hinzugefügt und weggenommen – es bleibt immer bei 20 Bytes.
Auch der AppVerifier meldet nur die Speicherzugriffsverletzung bei der Verwendung der bereits verschobenen Parameter :/
Das Offset lässt sich nicht modifizieren. Ich habe lokale Variablen hinzugefügt, entfernt, volatile gemacht (soweit es ging – bei Referenzen ist es ja z.B. unmöglich), Code hinzugefügt und weggenommen – es bleibt immer bei 20 Bytes.
Auch der AppVerifier meldet nur die Speicherzugriffsverletzung bei der Verwendung der bereits verschobenen Parameter :/
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] catch zerstört Funktionsparameter
Mal hierhin verschoben:
Was mir weiterhin sonderbar erscheint ist, dass ich dieselbe Funktion unmittelbar vorher mit zwei leicht verschiedenen Parametern aufrufe und dort alles glatt läuft, falls die Exception kommt. Selbst, wenn ich die Funktion mit exakt identischen Parametern aufrufe, kracht es. Das ist in sich inkonsistent – er kann unmöglich bei der dritten Ausführung derselben Exception eine andere Adresse ansteuern (die Funktion wird nicht geinlined, existiert also nur einmal) …
Okay, ich habe es gerade nochmal probiert und nun fliegt er mir auch bei den ersten beiden Aufrufen um die Ohren – hatte nicht die richtigen Dateien gelöscht, um die Exception auch definitiv fliegen zu lassen; sorry.
Ich habe das Problem jetzt irgendwie darauf eingrenzen können, dass es bei aktivierten Optimierungen auftritt (egal, ob Size oder Speed oder Full). Wie kriege ich das nun noch präziser eingegrenzt? Und bittebitte sagt nicht, dass ich die Command-Line von Hand tippen muss … dann werde ich nämlich bis zum Release von VS 2012 nicht mehr fertig.
Okay, Update: Ich habe einfach mal die Durschnittsmenge aller Direktiven genommen, die von allen drei Optimierungsstufen gesetzt wird, und das waren dann nur noch etwa fünf. Der problematische Switch ist /Og (Global Optimizations) – man soll ihn nicht manuell setzen, weil das deprecated ist, und ihn stattdessen von Optimize for Size / Speed / Full setzen lassen. Setze ich /Og, sind die Parameter verschoben und es kracht. Setze ich es nicht, läuft das Programm normal. Compiler-Bug?
Das hier klingt verdächtig; nur, dass es bei mir sowohl mit dem x64-Compiler als auch mit dem x86er auftritt. Wenn der Quelltext öffentlich einsehbar wäre, könnte ich vielleicht sehen, ob das meinem Konstrukt entspricht …
Okay, ich habe es gerade nochmal probiert und nun fliegt er mir auch bei den ersten beiden Aufrufen um die Ohren – hatte nicht die richtigen Dateien gelöscht, um die Exception auch definitiv fliegen zu lassen; sorry.
Ich habe das Problem jetzt irgendwie darauf eingrenzen können, dass es bei aktivierten Optimierungen auftritt (egal, ob Size oder Speed oder Full). Wie kriege ich das nun noch präziser eingegrenzt? Und bittebitte sagt nicht, dass ich die Command-Line von Hand tippen muss … dann werde ich nämlich bis zum Release von VS 2012 nicht mehr fertig.
Okay, Update: Ich habe einfach mal die Durschnittsmenge aller Direktiven genommen, die von allen drei Optimierungsstufen gesetzt wird, und das waren dann nur noch etwa fünf. Der problematische Switch ist /Og (Global Optimizations) – man soll ihn nicht manuell setzen, weil das deprecated ist, und ihn stattdessen von Optimize for Size / Speed / Full setzen lassen. Setze ich /Og, sind die Parameter verschoben und es kracht. Setze ich es nicht, läuft das Programm normal. Compiler-Bug?
Das hier klingt verdächtig; nur, dass es bei mir sowohl mit dem x64-Compiler als auch mit dem x86er auftritt. Wenn der Quelltext öffentlich einsehbar wäre, könnte ich vielleicht sehen, ob das meinem Konstrukt entspricht …
- kimmi
- Moderator
- Beiträge: 1412
- Registriert: 26.02.2009, 09:42
- Echter Name: Kim Kulling
- Wohnort: Luebeck
- Kontaktdaten:
Re: [C++] catch zerstört Funktionsparameter
Hast du schon mal bei MS nachgefragt, ob du da einem bekannten Problem auf die Spur gekommen bist? Und die 14 Byte waren einfach geraten. Ich wollte nur mal sehen, ob das von dir beschriebene Problem durch einen Stack-Overflow ausgelöst wurde.
Tritt das Verhalten eigentlich auch bei SEH auf?
Gruß Kimmi
Tritt das Verhalten eigentlich auch bei SEH auf?
Gruß Kimmi
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] catch zerstört Funktionsparameter
Ich wüsste nicht, wo ich da nachfragen sollte … es ist mir, wie gesagt, nicht gelungen, das Problem in einem Test-Case oder generell ohne einen 4 KiB großen .text-Block zu reproduzieren – damit ist es wohl nicht tauglich für einen Bug-Report bei Connect :/kimmi hat geschrieben:Hast du schon mal bei MS nachgefragt, ob du da einem bekannten Problem auf die Spur gekommen bist?
Okay … in einem Repro-Case wichen die Adressen innerhalb eines catch-Blocks nämlich tatsächlich mal 14 Bytes von den echten ab (oder ich habe das mit der Hex-Repräsentation von 20 Bytes verwechselt) … hätte ja sein können, dass es eine Magic Number im Exception-Handling ist.kimmi hat geschrieben:Und die 14 Byte waren einfach geraten.
Uff, gute Frage. Werde das heute abend mal testen.kimmi hat geschrieben:Tritt das Verhalten eigentlich auch bei SEH auf?
Edit: error C2712: Cannot use __try in functions that require object unwinding
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: (erledigt)[C++] catch zerstört Funktionsparameter
Sooo, mittlerweile habe ich ein Statement:
Damit ist die Sache endgültig geklärt. Sogar noch vor Weihnachten :)http://connect.microsoft.com/VisualStudio/feedback/details/624668 hat geschrieben:The problem is that the compiler is using EBX as a frame pointer register and not restoring the value of EBX in the catch.
The reason that the restore of EBX is missing is that it has inadvertently been optimized away.
A fix is in progress and will be included in the next major release of Visual Studio.
In the meantime this problem will be at risk of showing up whenever a parameter is accessed in a catch when the parameter pointer register is EBX. The compiler uses EBX as the parameter pointer register if the frame is dynamically aligned (e.g. because the function contains a local that requires than 4-byte alignment).
You can continue to run with optimizations disabled for functions that fit this description. Another possiblity is to access the parameters in a way that forces the compiler to not rely on EBX in the catch handler. For example, copy them into a local (probably a volatile one to avoid copy propagation) or copy them to a global variable. Both ways would avoid the compiler using EBX incorrectly in the catch handler.
- Schrompf
- Moderator
- Beiträge: 5161
- Registriert: 25.02.2009, 23:44
- Benutzertext: Lernt nur selten dazu
- Echter Name: Thomas
- Wohnort: Dresden
- Kontaktdaten:
Re: (erledigt)[C++] catch zerstört Funktionsparameter
Glückwunsch! Und allgemein als Entwickler: Danke für Dein Engagement!
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.